Skip to content

Commit

Permalink
docs: add docs for starknet-crypto (#634)
Browse files Browse the repository at this point in the history
  • Loading branch information
xJonathanLEI committed Jul 27, 2024
1 parent a989555 commit 02f2209
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 37 deletions.
12 changes: 6 additions & 6 deletions starknet-accounts/src/single_owner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@ where
{
/// Create a new account controlled by a single signer.
///
/// ### Arguments
/// ### Parameters
///
/// * `provider`: A `Provider` implementation that provides access to the Starknet network.
/// * `signer`: A `Signer` implementation that can generate valid signatures for this account.
/// * `address`: Account contract address.
/// * `chain_id`: Network chain ID.
/// * `encoding`: How `__execute__` calldata should be encoded.
/// - `provider`: A `Provider` implementation that provides access to the Starknet network.
/// - `signer`: A `Signer` implementation that can generate valid signatures for this account.
/// - `address`: Account contract address.
/// - `chain_id`: Network chain ID.
/// - `encoding`: How `__execute__` calldata should be encoded.
pub const fn new(
provider: P,
signer: S,
Expand Down
10 changes: 9 additions & 1 deletion starknet-crypto/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
# Low-level cryptography utilities for Starknet

`starknet-crypto` contains utilities for performing **low-level** cryptographic operations in Starknet.
`starknet-crypto` contains utilities for performing **low-level** cryptographic operations in Starknet:

- ECDSA operations
- Signing hashes
- Verifying signatures
- Recovering public keys from signatures
- Pedersen hash
- Poseidon hash
- RFC-6979

> _You're advised to use high-level crypto utilities implemented by the `starknet-core` crate (or use it through the `starknet::core` re-export) if you're not familiar with cryptographic primitives. Using these low-level functions incorrectly could result in leaking your private key, for example._
Expand Down
44 changes: 26 additions & 18 deletions starknet-crypto/src/ecdsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,22 @@ use crate::{
use starknet_types_core::curve::{AffinePoint, ProjectivePoint};
use starknet_types_core::felt::Felt;

/// The (exclusive) upper bound on many ECDSA-related elements based on the original C++
/// implementation from [`crypto-cpp`](https://github.com/starkware-libs/crypto-cpp).
///
/// The C++ implementation [imposes](https://github.com/starkware-libs/crypto-cpp/blob/78e3ed8dc7a0901fe6d62f4e99becc6e7936adfd/src/starkware/crypto/ecdsa.cc#L23)
/// an upper bound of `0x0800000000000000000000000000000000000000000000000000000000000000`.
///
/// When a compuated value is greater than or equal to this bound, the modulus is taken to ensure
/// the resulting value falls under the bound.
const ELEMENT_UPPER_BOUND: Felt = Felt::from_raw([
576459263475450960,
18446744073709255680,
160989183,
18446743986131435553,
]);

/// Stark ECDSA signature
/// Stark ECDSA signature.
#[derive(Debug)]
pub struct Signature {
/// The `r` value of a signature
Expand All @@ -23,7 +31,7 @@ pub struct Signature {
pub s: Felt,
}

/// Stark ECDSA signature with `v`
/// Stark ECDSA signature with `v`, useful for recovering the public key.
#[derive(Debug)]
pub struct ExtendedSignature {
/// The `r` value of a signature
Expand Down Expand Up @@ -70,9 +78,9 @@ impl core::fmt::Display for ExtendedSignature {

/// Computes the public key given a Stark private key.
///
/// ### Arguments
/// ### Parameters
///
/// * `private_key`: The private key
/// - `private_key`: The private key.
pub fn get_public_key(private_key: &Felt) -> Felt {
mul_by_bits(&GENERATOR, private_key)
.to_affine()
Expand All @@ -82,11 +90,11 @@ pub fn get_public_key(private_key: &Felt) -> Felt {

/// Computes ECDSA signature given a Stark private key and message hash.
///
/// ### Arguments
/// ### Parameters
///
/// * `private_key`: The private key
/// * `message`: The message hash
/// * `k`: A random `k` value. You **MUST NOT** use the same `k` on different signatures
/// - `private_key`: The private key.
/// - `message`: The message hash.
/// - `k`: A random `k` value. You **MUST NOT** use the same `k` on different signatures.
pub fn sign(private_key: &Felt, message: &Felt, k: &Felt) -> Result<ExtendedSignature, SignError> {
if message >= &ELEMENT_UPPER_BOUND {
return Err(SignError::InvalidMessageHash);
Expand Down Expand Up @@ -120,12 +128,12 @@ pub fn sign(private_key: &Felt, message: &Felt, k: &Felt) -> Result<ExtendedSign
/// Verifies if a signature is valid over a message hash given a public key. Returns an error
/// instead of `false` if the public key is invalid.
///
/// ### Arguments
/// ### Parameters
///
/// * `public_key`: The public key
/// * `message`: The message hash
/// * `r`: The `r` value of the signature
/// * `s`: The `s` value of the signature
/// - `public_key`: The public key.
/// - `message`: The message hash.
/// - `r`: The `r` value of the signature.
/// - `s`: The `s` value of the signature.
pub fn verify(public_key: &Felt, message: &Felt, r: &Felt, s: &Felt) -> Result<bool, VerifyError> {
if message >= &ELEMENT_UPPER_BOUND {
return Err(VerifyError::InvalidMessageHash);
Expand Down Expand Up @@ -162,12 +170,12 @@ pub fn verify(public_key: &Felt, message: &Felt, r: &Felt, s: &Felt) -> Result<b

/// Recovers the public key from a message and (r, s, v) signature parameters
///
/// ### Arguments
/// ### Parameters
///
/// * `msg_hash`: The message hash
/// * `r_bytes`: The `r` value of the signature
/// * `s_bytes`: The `s` value of the signature
/// * `v_bytes`: The `v` value of the signature
/// - `msg_hash`: The message hash.
/// - `r_bytes`: The `r` value of the signature.
/// - `s_bytes`: The `s` value of the signature.
/// - `v_bytes`: The `v` value of the signature.
pub fn recover(message: &Felt, r: &Felt, s: &Felt, v: &Felt) -> Result<Felt, RecoverError> {
if message >= &ELEMENT_UPPER_BOUND {
return Err(RecoverError::InvalidMessageHash);
Expand Down
18 changes: 15 additions & 3 deletions starknet-crypto/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
mod sign_error {
/// Errors when performing ECDSA [`sign`](fn.sign) operations
/// Errors when performing ECDSA [`sign`](fn.sign) operations.
#[derive(Debug)]
pub enum SignError {
/// The message hash is not in the range of `[0, 2^251)`.
InvalidMessageHash,
/// The random `k` value results in an invalid signature. A different `k` value should be
/// used instead, typically by using a new seed per RFC-6979.
InvalidK,
}

Expand All @@ -21,12 +24,16 @@ mod sign_error {
pub use sign_error::SignError;

mod verify_error {
/// Errors when performing ECDSA [`verify`](fn.verify) operations
/// Errors when performing ECDSA [`verify`](fn.verify) operations.
#[derive(Debug)]
pub enum VerifyError {
/// The public key is not a valid point on the STARK curve.
InvalidPublicKey,
/// The message hash is not in the range of `[0, 2^251)`.
InvalidMessageHash,
/// The `r` value is not in the range of `[0, 2^251)`.
InvalidR,
/// The `s` value is not in the range of `[0, 2^251)`.
InvalidS,
}

Expand All @@ -47,12 +54,17 @@ mod verify_error {
pub use verify_error::VerifyError;

mod recover_error {
/// Errors when performing ECDSA [`recover`](fn.recover) operations
/// Errors when performing ECDSA [`recover`](fn.recover) operations.
#[derive(Debug)]
pub enum RecoverError {
/// The message hash is not in the range of `[0, 2^251)`.
InvalidMessageHash,
/// The `r` value is not in the range of `[0, 2^251)`.
InvalidR,
/// The `s` value is not in the range of `[0,
/// 0x0800000000000010ffffffffffffffffb781126dcae7b2321e66a241adc64d2f)`.
InvalidS,
/// The `v` value is neither `0` nor `1`.
InvalidV,
}

Expand Down
18 changes: 17 additions & 1 deletion starknet-crypto/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
//! Low-level cryptography utilities for Starknet. Features include:
//!
//! - ECDSA operations
//! - [Signing hashes](fn.sign)
//! - [Verifying signatures](fn.verify)
//! - [Recovering public keys from signatures](fn.recover)
//! - [Pedersen hash](fn.pedersen_hash)
//! - Poseidon hash
//! - [RFC-6979](fn.rfc6979_generate_k)
//!
//! # Warning
//!
//! You're advised to use high-level crypto utilities implemented by the `starknet-core` crate if
//! you're not familiar with cryptographic primitives. Using these low-level functions incorrectly
//! could result in catastrophic consequences like leaking your private key.

#![deny(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
#![doc = include_str!("../README.md")]

#[allow(unused_extern_crates)]
#[cfg(all(not(feature = "std"), any(test, feature = "alloc")))]
Expand Down
6 changes: 3 additions & 3 deletions starknet-crypto/src/pedersen_hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ use starknet_types_core::{

/// Computes the Starkware version of the Pedersen hash of x and y. All inputs are little-endian.
///
/// ### Arguments
/// ### Parameters
///
/// * `x`: The x coordinate
/// * `y`: The y coordinate
/// - `x`: The x coordinate.
/// - `y`: The y coordinate.
pub fn pedersen_hash(x: &Felt, y: &Felt) -> Felt {
Pedersen::hash(x, y)
}
Expand Down
2 changes: 1 addition & 1 deletion starknet-crypto/src/poseidon_hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use starknet_types_core::{felt::Felt, hash::Poseidon};

/// A hasher for Starknet Poseidon hash.
/// A stateful hasher for Starknet Poseidon hash.
///
/// Using this hasher is the same as calling [`poseidon_hash_many`].
#[derive(Debug, Default)]
Expand Down
8 changes: 4 additions & 4 deletions starknet-crypto/src/rfc6979.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ const EC_ORDER: U256 =

/// Deterministically generate ephemeral scalar `k` based on RFC 6979.
///
/// ### Arguments
/// ### Parameters
///
/// * `message_hash`: message hash
/// * `private_key`: private key
/// * `seed`: extra seed for additional entropy
/// - `message_hash`: Message hash.
/// - `private_key`: Private key.
/// - `seed`: Extra seed for additional entropy.
pub fn generate_k(message_hash: &Felt, private_key: &Felt, seed: Option<&Felt>) -> Felt {
// The message hash padding as implemented in `cairo-lang` is not needed here. The hash is
// padded in `cairo-lang` only to make sure the lowest 4 bits won't get truncated, but here it's
Expand Down

0 comments on commit 02f2209

Please sign in to comment.