Skip to content

Commit

Permalink
docs: add docs for starknet-signers (#638)
Browse files Browse the repository at this point in the history
  • Loading branch information
xJonathanLEI authored Jul 29, 2024
1 parent 3a5537a commit 4726535
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 1 deletion.
14 changes: 14 additions & 0 deletions starknet-signers/src/key_pair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,29 @@ use starknet_core::{
};
use starknet_crypto::get_public_key;

/// A ECDSA signing (private) key on the STARK curve.
#[derive(Debug, Clone)]
pub struct SigningKey {
secret_scalar: Felt,
}

/// A ECDSA verifying (public) key on the STARK curve.
#[derive(Debug, Clone)]
pub struct VerifyingKey {
scalar: Felt,
}

/// Errors using an encrypted JSON keystore.
#[cfg(not(target_arch = "wasm32"))]
#[derive(Debug, thiserror::Error)]
pub enum KeystoreError {
/// The file path is invalid.
#[error("invalid path")]
InvalidPath,
/// The decrypted secret scalar is not a valid private key.
#[error("invalid decrypted secret scalar")]
InvalidScalar,
/// Upstream `eth-keystore` error propagated.
#[error(transparent)]
Inner(eth_keystore::KeystoreError),
}
Expand All @@ -47,6 +53,7 @@ impl SigningKey {
Self { secret_scalar }
}

/// Constructs [`SigningKey`] directly from a secret scalar.
pub const fn from_secret_scalar(secret_scalar: Felt) -> Self {
Self { secret_scalar }
}
Expand Down Expand Up @@ -92,28 +99,35 @@ impl SigningKey {
Ok(())
}

/// Gets the secret scalar in the signing key.
pub const fn secret_scalar(&self) -> Felt {
self.secret_scalar
}

/// Derives the verifying (public) key that corresponds to the signing key.
pub fn verifying_key(&self) -> VerifyingKey {
VerifyingKey::from_scalar(get_public_key(&self.secret_scalar))
}

/// Signs a raw hash using ECDSA for a signature.
pub fn sign(&self, hash: &Felt) -> Result<Signature, EcdsaSignError> {
ecdsa_sign(&self.secret_scalar, hash).map(|sig| sig.into())
}
}

impl VerifyingKey {
/// Constructs [`VerifyingKey`] directly from a scalar.
pub const fn from_scalar(scalar: Felt) -> Self {
Self { scalar }
}

/// Gets the scalar in the verifying key.
pub const fn scalar(&self) -> Felt {
self.scalar
}

/// Verifies that an ECDSA signature is valid for the verifying key against a certain message
/// hash.
pub fn verify(&self, hash: &Felt, signature: &Signature) -> Result<bool, EcdsaVerifyError> {
ecdsa_verify(&self.scalar, hash, signature)
}
Expand Down
13 changes: 12 additions & 1 deletion starknet-signers/src/ledger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,29 @@ pub struct LedgerStarknetApp {
transport: Ledger,
}

/// Errors using the Ledger hardware wallet.
#[derive(Debug, thiserror::Error)]
pub enum LedgerError {
/// The HD wallet derivation path is malformed or does not conform to EIP-2645.
#[error("derivation path is empty, not prefixed with m/2645', or is not 6-level long")]
InvalidDerivationPath,
/// Error communicating with the Ledger hardware device.
#[error(transparent)]
TransportError(coins_ledger::LedgerError),
/// An unknown response code is returned from the device.
#[error("unknown response code from Ledger: {0}")]
UnknownResponseCode(u16),
/// The response code returned from the device does not indicate success.
#[error("failed Ledger request: {0}")]
UnsuccessfulRequest(APDUResponseCodes),
/// The response has an unexpected size.
#[error("unexpected response length - expected: {expected}; actual: {actual}")]
UnexpectedResponseLength { expected: usize, actual: usize },
UnexpectedResponseLength {
/// The expected response size.
expected: usize,
/// The actual response size.
actual: usize,
},
}

/// The `GetPubKey` Ledger command.
Expand Down
8 changes: 8 additions & 0 deletions starknet-signers/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
//! Starknet signer interface and common implementations.
#![deny(missing_docs)]

mod key_pair;
pub use key_pair::{SigningKey, VerifyingKey};

Expand All @@ -7,13 +11,17 @@ pub use key_pair::KeystoreError;
mod signer;
pub use signer::Signer;

/// Module containing types related to the use of a simple in-memory signer.
pub mod local_wallet;
pub use local_wallet::LocalWallet;

/// Module containing types related to the Ledger hardware wallet.
#[cfg(feature = "ledger")]
pub mod ledger;
#[cfg(feature = "ledger")]
pub use ledger::{DerivationPath, LedgerError, LedgerSigner};

/// An error type that indicates an error cannot possibly occur. Used as placeholder where
/// [`Result`] is expected.
#[derive(Debug, thiserror::Error)]
pub enum Infallible {}
5 changes: 5 additions & 0 deletions starknet-signers/src/local_wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,23 @@ use starknet_core::{
types::Felt,
};

/// A signer that simply holds the signing (private) key in memory for performing cryptographic
/// operations. It's recommended to use hardware-based signers for use cases involving real value.
#[derive(Debug, Clone)]
pub struct LocalWallet {
private_key: SigningKey,
}

/// Errors using [`LocalWallet`].
#[derive(Debug, thiserror::Error)]
pub enum SignError {
/// ECDSA signature error.
#[error(transparent)]
EcdsaSignError(EcdsaSignError),
}

impl LocalWallet {
/// Constructs [`LocalWallet`] from a [`SigningKey`].
pub fn from_signing_key(key: SigningKey) -> Self {
key.into()
}
Expand Down
14 changes: 14 additions & 0 deletions starknet-signers/src/signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,29 @@ use auto_impl::auto_impl;
use starknet_core::{crypto::Signature, types::Felt};
use std::error::Error;

/// Any signer that can provide a public key as [`Felt`], and sign a raw hash for a signature
/// encoded as [`Vec<Felt>`].
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[auto_impl(&, Box, Arc)]
pub trait Signer {
/// Possible errors for calling [`get_public_key`](fn.get_public_key).
type GetPublicKeyError: Error + Send + Sync;
/// Possible errors for calling [`sign`](fn.sign).
type SignError: Error + Send + Sync;

/// Retrieves the verifying (public) key from the signer.
async fn get_public_key(&self) -> Result<VerifyingKey, Self::GetPublicKeyError>;

/// Requests an ECDSA signature for a message hash.
///
/// Signing a raw hash is known as "blind signing". For interactive signers (e.g. hardware
/// wallets) that can theoretically provide better security properties via "clear signing",
/// using blind signing is bad practice.
///
/// However, as of this writing, no actual interactive signer implementation offers clear
/// signing. When this changes in the future, this trait shall be altered to allow such clear
/// signing capabilities.
async fn sign_hash(&self, hash: &Felt) -> Result<Signature, Self::SignError>;

/// Whether the underlying signer implementation is interactive, such as a hardware wallet.
Expand Down

0 comments on commit 4726535

Please sign in to comment.