DIY Digital Signatures

Hi. I'm creating a tutorial exploring some of the core concepts used to build blockchains. It has english explanations and working Rust code. The goal is to make it simple and accessible with everything running in mdBook or the Rust Playground. This means no calling external libraries for things like crypto and digital signatures.

With that in mind, does anyone know how to roll a simple (low complexity and computation) function that would:

  • hash the concatenation of a struct (transaction) and a String (private signing key)
  • and that can also be verified against the public address associated with that signature (public key)
  • this way someone can sign a transaction to verify that it's authentic vs anyone being able to create transactions arbitrarily

It does not have to be "secure" from a cryptographic standpoint. It just needs to work so that someone can experiment with it in context with other blockchain mechanisms. I know that's vague, but any help or resources would be greatly appreciated! Thanks :slight_smile:

// Here's an example

// Struct that holds transaction data
struct TX {
    sender: String,
    receiver: String,
    tx_amount: f32,
    nonce: i32,

// Struct that holds a transaction
// and a transaction signature making it valid
struct Signed_TX {
    tx: TX,
    signature: String,

// I need a function that can perform digital signatures by
// hashing the TX Struct with a private key, and that also
// allows people to verify that signature against the private
// key's corresponding public key.
// The keys can be very very small.
// The signature can be insecure.
// It just needs to use standard Rust code :)

Well, I guess you can hack something using the Hash trait that is mainly used by Map AFAIK. (iirc there's SipHash somewhere in std)

I just worry that someone might look at your example code and figure that that's a legitimate signature scheme.

1 Like

If this is a request for a "toy" public-key signature function, you might need to roll your own. The simplest way to do that might be to implement this function in Rust.

Alternatively, you could use a public-key signature function from libsodium, which "is conjectured to meet the standard notion of unforgeability for a public-key signature scheme under chosen-message attacks." Rust bindings to libsodium can be found on in a package called sodiumoxide. The library subset for public-key signatures can be found here.

1 Like

Thanks for your responses! Very helpful :slight_smile:

I was looking through the Hash docs and it said that std::hash::SipHasher is depreciated. Even if I were to use another hash function though, from the little I know hashes are mainly for content addressing and timestamping, but not pub/priv key verification right? Or am I missing something?

It's just a tutorial to understand the core concepts. Once I have the general structure in place, then the tutorial will go through each function explaining what it does and how to make it better as well as linking to a library used in production. The tutorial is meant as a bridge between generic high level blog posts and production ready code. Pretty much just creating the tutorials I always wished existed :slight_smile:

@TomP Yes! While there's a lot great libraries for pub/priv key protocols I'd like to roll it in the tutorial so that users can see exactly what's happening without a call to an external library. I'm going to try to replicate the example you provided. Thanks :slight_smile:

Alright, so I got a basic prototype working here:

Any feedback/suggestions to make it more readable or compact would be warmly welcomed :slight_smile:

Also, when I tried to upload it to mdBook here it failed because mdBook could not find the external crate rand. The Rust Cookbook uses rand, and it works in the Rust Playground, so does anyone know how to add rand to mdBook?

1 Like

I'd recommend using this option: It's a bit low-level, though it seems it's all that we have. This other crate uses it by having another crate depending on the dependencies (in this case rand), using cargo build on that crate first, then pointing mdbook to that crate's built dependencies directory.

If you're interested in feedback on the code itself, I can't seem to find any place you're using negative numbers. Have you considered switching to u32 instead of i32? It'd allow leaving out the check on line 46, and more compile time assurance seems like a good thing. It looks like a great example regardless! (though I can't judge if there's anything missing as I haven't researched RSA in depth).

1 Like

Thanks! :slight_smile:

I saw that the Rust Cookbook had a Cargo.toml file as well as a file (with just a print statement as a placeholder) even though mdBook init doesn't create or need those files. Tried adding both to my repo and building it, but that didn't seem to make any change. Are you saying that I can point mdBook to the build either in the travis.yml file or via the command line?

Also, the reason it's using i32 instead of u32 is that I wanted to reduce the complexity for people new to Rust. At the moment it's a mirror of a tutorial that's written in JavaScript so I want to introduce as few new concepts at a time to make it easier for people to explore the code. Also, in my experiments u32 would cause errors on the Rust Playground at much lower values than i32. Since the keys are initialized randomly that can get annoying to the user if half the time the process fails. Might just be because I did a poor job in my u8 implementation though.

I don't think mdBook will hook into another crate automatically, but it will if you pre-build the dependencies, and tell it exactly where those dependencies are. The other crates I saw doing it did something like this in their .travis.yml files:

cargo build
mdbook test -L target/debug/deps
1 Like