2018-11-16 08:04:46 -08:00
|
|
|
//! The `signature` module provides functionality for public, and private keys.
|
2020-10-24 08:39:28 -07:00
|
|
|
#![cfg(feature = "full")]
|
2018-11-16 08:04:46 -08:00
|
|
|
|
2021-05-06 23:51:52 -07:00
|
|
|
use crate::pubkey::Pubkey;
|
2019-11-07 17:08:10 -08:00
|
|
|
use generic_array::{typenum::U64, GenericArray};
|
|
|
|
use std::{
|
|
|
|
borrow::{Borrow, Cow},
|
2020-07-23 16:23:51 -07:00
|
|
|
convert::TryInto,
|
2021-05-06 23:51:52 -07:00
|
|
|
fmt, mem,
|
2019-11-07 17:08:10 -08:00
|
|
|
str::FromStr,
|
|
|
|
};
|
2020-02-13 16:53:09 -08:00
|
|
|
use thiserror::Error;
|
2018-11-16 08:04:46 -08:00
|
|
|
|
2021-05-06 23:51:52 -07:00
|
|
|
// legacy module paths
|
2021-05-07 01:06:20 -07:00
|
|
|
pub use crate::signer::{keypair::*, null_signer::*, presigner::*, *};
|
2018-11-16 08:04:46 -08:00
|
|
|
|
2021-01-20 14:07:15 -08:00
|
|
|
/// Number of bytes in a signature
|
|
|
|
pub const SIGNATURE_BYTES: usize = 64;
|
|
|
|
/// Maximum string length of a base58 encoded signature
|
|
|
|
const MAX_BASE58_SIGNATURE_LEN: usize = 88;
|
|
|
|
|
2019-07-15 12:17:17 -07:00
|
|
|
#[repr(transparent)]
|
2020-07-06 04:22:23 -07:00
|
|
|
#[derive(
|
|
|
|
Serialize, Deserialize, Clone, Copy, Default, Eq, PartialEq, Ord, PartialOrd, Hash, AbiExample,
|
|
|
|
)]
|
2018-11-16 08:04:46 -08:00
|
|
|
pub struct Signature(GenericArray<u8, U64>);
|
|
|
|
|
2020-04-27 11:06:00 -07:00
|
|
|
impl crate::sanitize::Sanitize for Signature {}
|
|
|
|
|
2018-11-16 08:04:46 -08:00
|
|
|
impl Signature {
|
|
|
|
pub fn new(signature_slice: &[u8]) -> Self {
|
2019-03-17 19:48:12 -07:00
|
|
|
Self(GenericArray::clone_from_slice(&signature_slice))
|
2018-11-16 08:04:46 -08:00
|
|
|
}
|
|
|
|
|
2020-07-30 17:10:41 -07:00
|
|
|
pub(self) fn verify_verbose(
|
|
|
|
&self,
|
|
|
|
pubkey_bytes: &[u8],
|
|
|
|
message_bytes: &[u8],
|
|
|
|
) -> Result<(), ed25519_dalek::SignatureError> {
|
|
|
|
let publickey = ed25519_dalek::PublicKey::from_bytes(pubkey_bytes)?;
|
|
|
|
let signature = self.0.as_slice().try_into()?;
|
|
|
|
publickey.verify_strict(message_bytes, &signature)
|
|
|
|
}
|
|
|
|
|
2018-11-16 08:04:46 -08:00
|
|
|
pub fn verify(&self, pubkey_bytes: &[u8], message_bytes: &[u8]) -> bool {
|
2020-07-30 17:10:41 -07:00
|
|
|
self.verify_verbose(pubkey_bytes, message_bytes).is_ok()
|
2018-11-16 08:04:46 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-01 12:00:30 -08:00
|
|
|
pub trait Signable {
|
|
|
|
fn sign(&mut self, keypair: &Keypair) {
|
2019-06-12 16:43:05 -07:00
|
|
|
let signature = keypair.sign_message(self.signable_data().borrow());
|
|
|
|
self.set_signature(signature);
|
2018-12-01 12:00:30 -08:00
|
|
|
}
|
|
|
|
fn verify(&self) -> bool {
|
|
|
|
self.get_signature()
|
2019-06-12 16:43:05 -07:00
|
|
|
.verify(&self.pubkey().as_ref(), self.signable_data().borrow())
|
2018-12-01 12:00:30 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn pubkey(&self) -> Pubkey;
|
2019-06-12 16:43:05 -07:00
|
|
|
fn signable_data(&self) -> Cow<[u8]>;
|
2018-12-01 12:00:30 -08:00
|
|
|
fn get_signature(&self) -> Signature;
|
|
|
|
fn set_signature(&mut self, signature: Signature);
|
|
|
|
}
|
|
|
|
|
2018-11-16 08:04:46 -08:00
|
|
|
impl AsRef<[u8]> for Signature {
|
|
|
|
fn as_ref(&self) -> &[u8] {
|
|
|
|
&self.0[..]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Debug for Signature {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "{}", bs58::encode(self.0).into_string())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for Signature {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "{}", bs58::encode(self.0).into_string())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-23 11:55:15 -08:00
|
|
|
impl From<Signature> for [u8; 64] {
|
|
|
|
fn from(signature: Signature) -> Self {
|
|
|
|
signature.0.into()
|
2019-07-15 12:17:17 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-12 23:20:49 -07:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Error)]
|
2019-05-16 14:54:31 -07:00
|
|
|
pub enum ParseSignatureError {
|
2020-03-12 23:20:49 -07:00
|
|
|
#[error("string decoded to wrong size for signature")]
|
2019-05-16 14:54:31 -07:00
|
|
|
WrongSize,
|
2020-03-12 23:20:49 -07:00
|
|
|
#[error("failed to decode string to signature")]
|
2019-05-16 14:54:31 -07:00
|
|
|
Invalid,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FromStr for Signature {
|
|
|
|
type Err = ParseSignatureError;
|
|
|
|
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
2021-01-20 14:07:15 -08:00
|
|
|
if s.len() > MAX_BASE58_SIGNATURE_LEN {
|
|
|
|
return Err(ParseSignatureError::WrongSize);
|
|
|
|
}
|
2019-05-16 14:54:31 -07:00
|
|
|
let bytes = bs58::decode(s)
|
|
|
|
.into_vec()
|
|
|
|
.map_err(|_| ParseSignatureError::Invalid)?;
|
|
|
|
if bytes.len() != mem::size_of::<Signature>() {
|
|
|
|
Err(ParseSignatureError::WrongSize)
|
|
|
|
} else {
|
|
|
|
Ok(Signature::new(&bytes))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-18 13:37:20 -07:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
2019-05-16 14:54:31 -07:00
|
|
|
#[test]
|
|
|
|
fn test_signature_fromstr() {
|
|
|
|
let signature = Keypair::new().sign_message(&[0u8]);
|
|
|
|
|
|
|
|
let mut signature_base58_str = bs58::encode(signature).into_string();
|
|
|
|
|
|
|
|
assert_eq!(signature_base58_str.parse::<Signature>(), Ok(signature));
|
|
|
|
|
|
|
|
signature_base58_str.push_str(&bs58::encode(signature.0).into_string());
|
|
|
|
assert_eq!(
|
|
|
|
signature_base58_str.parse::<Signature>(),
|
|
|
|
Err(ParseSignatureError::WrongSize)
|
|
|
|
);
|
|
|
|
|
|
|
|
signature_base58_str.truncate(signature_base58_str.len() / 2);
|
|
|
|
assert_eq!(signature_base58_str.parse::<Signature>(), Ok(signature));
|
|
|
|
|
|
|
|
signature_base58_str.truncate(signature_base58_str.len() / 2);
|
|
|
|
assert_eq!(
|
|
|
|
signature_base58_str.parse::<Signature>(),
|
|
|
|
Err(ParseSignatureError::WrongSize)
|
|
|
|
);
|
|
|
|
|
|
|
|
let mut signature_base58_str = bs58::encode(signature.0).into_string();
|
|
|
|
assert_eq!(signature_base58_str.parse::<Signature>(), Ok(signature));
|
|
|
|
|
|
|
|
// throw some non-base58 stuff in there
|
|
|
|
signature_base58_str.replace_range(..1, "I");
|
|
|
|
assert_eq!(
|
|
|
|
signature_base58_str.parse::<Signature>(),
|
|
|
|
Err(ParseSignatureError::Invalid)
|
|
|
|
);
|
2021-01-20 14:07:15 -08:00
|
|
|
|
|
|
|
// too long input string
|
|
|
|
// longest valid encoding
|
|
|
|
let mut too_long = bs58::encode(&[255u8; SIGNATURE_BYTES]).into_string();
|
|
|
|
// and one to grow on
|
|
|
|
too_long.push('1');
|
|
|
|
assert_eq!(
|
|
|
|
too_long.parse::<Signature>(),
|
|
|
|
Err(ParseSignatureError::WrongSize)
|
|
|
|
);
|
2019-05-16 14:54:31 -07:00
|
|
|
}
|
2019-11-22 07:20:40 -08:00
|
|
|
|
2020-07-30 17:11:16 -07:00
|
|
|
#[test]
|
|
|
|
fn test_off_curve_pubkey_verify_fails() {
|
|
|
|
// Golden point off the ed25519 curve
|
|
|
|
let off_curve_bytes = bs58::decode("9z5nJyQar1FUxVJxpBXzon6kHehbomeYiDaLi9WAMhCq")
|
|
|
|
.into_vec()
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
// Confirm golden's off-curvedness
|
|
|
|
let mut off_curve_bits = [0u8; 32];
|
|
|
|
off_curve_bits.copy_from_slice(&off_curve_bytes);
|
|
|
|
let off_curve_point = curve25519_dalek::edwards::CompressedEdwardsY(off_curve_bits);
|
|
|
|
assert_eq!(off_curve_point.decompress(), None);
|
|
|
|
|
|
|
|
let pubkey = Pubkey::new(&off_curve_bytes);
|
|
|
|
let signature = Signature::default();
|
|
|
|
// Unfortunately, ed25519-dalek doesn't surface the internal error types that we'd ideally
|
|
|
|
// `source()` out of the `SignatureError` returned by `verify_strict()`. So the best we
|
|
|
|
// can do is `is_err()` here.
|
|
|
|
assert!(signature.verify_verbose(pubkey.as_ref(), &[0u8]).is_err());
|
|
|
|
}
|
2019-04-18 13:37:20 -07:00
|
|
|
}
|