sdk: Move Signer
trait to own module
This commit is contained in:
parent
d4ffd909a4
commit
af6f3d776e
@ -40,6 +40,7 @@ pub mod rpc_port;
|
|||||||
pub mod secp256k1_instruction;
|
pub mod secp256k1_instruction;
|
||||||
pub mod shred_version;
|
pub mod shred_version;
|
||||||
pub mod signature;
|
pub mod signature;
|
||||||
|
pub mod signer;
|
||||||
pub mod signers;
|
pub mod signers;
|
||||||
pub mod stake_weighted_timestamp;
|
pub mod stake_weighted_timestamp;
|
||||||
pub mod system_transaction;
|
pub mod system_transaction;
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
//! The `signature` module provides functionality for public, and private keys.
|
//! The `signature` module provides functionality for public, and private keys.
|
||||||
#![cfg(feature = "full")]
|
#![cfg(feature = "full")]
|
||||||
|
|
||||||
use crate::{derivation_path::DerivationPath, pubkey::Pubkey, transaction::TransactionError};
|
use crate::{derivation_path::DerivationPath, pubkey::Pubkey};
|
||||||
use ed25519_dalek::Signer as DalekSigner;
|
use ed25519_dalek::Signer as DalekSigner;
|
||||||
use ed25519_dalek_bip32::Error as Bip32Error;
|
use ed25519_dalek_bip32::Error as Bip32Error;
|
||||||
use generic_array::{typenum::U64, GenericArray};
|
use generic_array::{typenum::U64, GenericArray};
|
||||||
use hmac::Hmac;
|
use hmac::Hmac;
|
||||||
use itertools::Itertools;
|
|
||||||
use rand::{rngs::OsRng, CryptoRng, RngCore};
|
use rand::{rngs::OsRng, CryptoRng, RngCore};
|
||||||
use std::{
|
use std::{
|
||||||
borrow::{Borrow, Cow},
|
borrow::{Borrow, Cow},
|
||||||
@ -20,6 +19,9 @@ use std::{
|
|||||||
};
|
};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
// legacy module paths
|
||||||
|
pub use crate::signer::*;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Keypair(ed25519_dalek::Keypair);
|
pub struct Keypair(ed25519_dalek::Keypair);
|
||||||
|
|
||||||
@ -158,34 +160,6 @@ impl FromStr for Signature {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Signer {
|
|
||||||
fn pubkey(&self) -> Pubkey {
|
|
||||||
self.try_pubkey().unwrap_or_default()
|
|
||||||
}
|
|
||||||
fn try_pubkey(&self) -> Result<Pubkey, SignerError>;
|
|
||||||
fn sign_message(&self, message: &[u8]) -> Signature {
|
|
||||||
self.try_sign_message(message).unwrap_or_default()
|
|
||||||
}
|
|
||||||
fn try_sign_message(&self, message: &[u8]) -> Result<Signature, SignerError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for dyn Signer {
|
|
||||||
fn eq(&self, other: &dyn Signer) -> bool {
|
|
||||||
self.pubkey() == other.pubkey()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Debug for dyn Signer {
|
|
||||||
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
||||||
write!(fmt, "Signer: {:?}", self.pubkey())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Remove duplicates signers while preserving order. O(n²)
|
|
||||||
pub fn unique_signers(signers: Vec<&dyn Signer>) -> Vec<&dyn Signer> {
|
|
||||||
signers.into_iter().unique_by(|s| s.pubkey()).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Signer for Keypair {
|
impl Signer for Keypair {
|
||||||
/// Return the public key for the given keypair
|
/// Return the public key for the given keypair
|
||||||
fn pubkey(&self) -> Pubkey {
|
fn pubkey(&self) -> Pubkey {
|
||||||
@ -214,50 +188,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> From<T> for Box<dyn Signer>
|
|
||||||
where
|
|
||||||
T: Signer + 'static,
|
|
||||||
{
|
|
||||||
fn from(signer: T) -> Self {
|
|
||||||
Box::new(signer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Error, PartialEq)]
|
|
||||||
pub enum SignerError {
|
|
||||||
#[error("keypair-pubkey mismatch")]
|
|
||||||
KeypairPubkeyMismatch,
|
|
||||||
|
|
||||||
#[error("not enough signers")]
|
|
||||||
NotEnoughSigners,
|
|
||||||
|
|
||||||
#[error("transaction error")]
|
|
||||||
TransactionError(#[from] TransactionError),
|
|
||||||
|
|
||||||
#[error("custom error: {0}")]
|
|
||||||
Custom(String),
|
|
||||||
|
|
||||||
// Presigner-specific Errors
|
|
||||||
#[error("presigner error")]
|
|
||||||
PresignerError(#[from] PresignerError),
|
|
||||||
|
|
||||||
// Remote Keypair-specific Errors
|
|
||||||
#[error("connection error: {0}")]
|
|
||||||
Connection(String),
|
|
||||||
|
|
||||||
#[error("invalid input: {0}")]
|
|
||||||
InvalidInput(String),
|
|
||||||
|
|
||||||
#[error("no device found")]
|
|
||||||
NoDeviceFound,
|
|
||||||
|
|
||||||
#[error("{0}")]
|
|
||||||
Protocol(String),
|
|
||||||
|
|
||||||
#[error("{0}")]
|
|
||||||
UserCancel(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct Presigner {
|
pub struct Presigner {
|
||||||
pubkey: Pubkey,
|
pubkey: Pubkey,
|
||||||
@ -629,20 +559,6 @@ mod tests {
|
|||||||
assert_eq!(presigner, presigner2);
|
assert_eq!(presigner, presigner2);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pubkeys(signers: &[&dyn Signer]) -> Vec<Pubkey> {
|
|
||||||
signers.iter().map(|x| x.pubkey()).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_unique_signers() {
|
|
||||||
let alice = Keypair::new();
|
|
||||||
let bob = Keypair::new();
|
|
||||||
assert_eq!(
|
|
||||||
pubkeys(&unique_signers(vec![&alice, &bob, &alice])),
|
|
||||||
pubkeys(&[&alice, &bob])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_off_curve_pubkey_verify_fails() {
|
fn test_off_curve_pubkey_verify_fails() {
|
||||||
// Golden point off the ed25519 curve
|
// Golden point off the ed25519 curve
|
||||||
|
114
sdk/src/signer/mod.rs
Normal file
114
sdk/src/signer/mod.rs
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
#![cfg(feature = "full")]
|
||||||
|
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
pubkey::Pubkey,
|
||||||
|
signature::{PresignerError, Signature},
|
||||||
|
transaction::TransactionError,
|
||||||
|
},
|
||||||
|
itertools::Itertools,
|
||||||
|
thiserror::Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub mod keypair;
|
||||||
|
|
||||||
|
#[derive(Debug, Error, PartialEq)]
|
||||||
|
pub enum SignerError {
|
||||||
|
#[error("keypair-pubkey mismatch")]
|
||||||
|
KeypairPubkeyMismatch,
|
||||||
|
|
||||||
|
#[error("not enough signers")]
|
||||||
|
NotEnoughSigners,
|
||||||
|
|
||||||
|
#[error("transaction error")]
|
||||||
|
TransactionError(#[from] TransactionError),
|
||||||
|
|
||||||
|
#[error("custom error: {0}")]
|
||||||
|
Custom(String),
|
||||||
|
|
||||||
|
// Presigner-specific Errors
|
||||||
|
#[error("presigner error")]
|
||||||
|
PresignerError(#[from] PresignerError),
|
||||||
|
|
||||||
|
// Remote Keypair-specific Errors
|
||||||
|
#[error("connection error: {0}")]
|
||||||
|
Connection(String),
|
||||||
|
|
||||||
|
#[error("invalid input: {0}")]
|
||||||
|
InvalidInput(String),
|
||||||
|
|
||||||
|
#[error("no device found")]
|
||||||
|
NoDeviceFound,
|
||||||
|
|
||||||
|
#[error("{0}")]
|
||||||
|
Protocol(String),
|
||||||
|
|
||||||
|
#[error("{0}")]
|
||||||
|
UserCancel(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The `Signer` trait declares operations that all digital signature providers
|
||||||
|
/// must support. It is the primary interface by which signers are specified in
|
||||||
|
/// `Transaction` signing interfaces
|
||||||
|
pub trait Signer {
|
||||||
|
/// Infallibly gets the implementor's public key. Returns the all-zeros
|
||||||
|
/// `Pubkey` if the implementor has none.
|
||||||
|
fn pubkey(&self) -> Pubkey {
|
||||||
|
self.try_pubkey().unwrap_or_default()
|
||||||
|
}
|
||||||
|
/// Fallibly gets the implementor's public key
|
||||||
|
fn try_pubkey(&self) -> Result<Pubkey, SignerError>;
|
||||||
|
/// Invallibly produces an Ed25519 signature over the provided `message`
|
||||||
|
/// bytes. Returns the all-zeros `Signature` if signing is not possible.
|
||||||
|
fn sign_message(&self, message: &[u8]) -> Signature {
|
||||||
|
self.try_sign_message(message).unwrap_or_default()
|
||||||
|
}
|
||||||
|
/// Fallibly produces an Ed25519 signature over the provided `message` bytes.
|
||||||
|
fn try_sign_message(&self, message: &[u8]) -> Result<Signature, SignerError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<T> for Box<dyn Signer>
|
||||||
|
where
|
||||||
|
T: Signer + 'static,
|
||||||
|
{
|
||||||
|
fn from(signer: T) -> Self {
|
||||||
|
Box::new(signer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for dyn Signer {
|
||||||
|
fn eq(&self, other: &dyn Signer) -> bool {
|
||||||
|
self.pubkey() == other.pubkey()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for dyn Signer {
|
||||||
|
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(fmt, "Signer: {:?}", self.pubkey())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes duplicate signers while preserving order. O(n²)
|
||||||
|
pub fn unique_signers(signers: Vec<&dyn Signer>) -> Vec<&dyn Signer> {
|
||||||
|
signers.into_iter().unique_by(|s| s.pubkey()).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::signer::keypair::Keypair;
|
||||||
|
|
||||||
|
fn pubkeys(signers: &[&dyn Signer]) -> Vec<Pubkey> {
|
||||||
|
signers.iter().map(|x| x.pubkey()).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_unique_signers() {
|
||||||
|
let alice = Keypair::new();
|
||||||
|
let bob = Keypair::new();
|
||||||
|
assert_eq!(
|
||||||
|
pubkeys(&unique_signers(vec![&alice, &bob, &alice])),
|
||||||
|
pubkeys(&[&alice, &bob])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user