Schnorr Signatures in Go

Kenta Iwasaki
Coinmonks
7 min readApr 5, 2018

--

Figured that while I’m getting into the mess of cryptography and some funky prime curve cyclic number theory, and learning Golang for a new startup I’m working on, I might as well try cover the Schnorr signature scheme in Go.

Let’s work with an asymmetric cryptosystem based off of the discrete log problem (any ‘ole one that deals with elliptic curves would do).

To simplify operations working with elliptic curves, we’ll utilize a handy library dedis/kyber.

Here are our imports as usual:

To signify how nice kyber is as a library, we define the base point of an elliptic curve to be a generator G. By picking a random scalar to be our private key x, we can derive our public key y which is y = x * G.

In other words, we perform operations in the additive group of our elliptic curve x times.

Everything above could be represented in the following code:

As you may have guessed from the curve, we’re going to be working with the elliptic curve group Edwards 25519 which is popularly used by another signature scheme variant known as EdDSA.

For our hashing function which will fingerprint our message to be signed, we’ll be using SHA256.

We’ll also define a nice struct to hold some set of data that’ll represent our messages signature, and our plain-text hashing function

So, let’s dive into the scheme.

Working around the discrete log scenario, we will be taking advantage of a trapdoor function which basically stands for a function whose inverse is extremely difficult to compute.

Thankfully, as the hash we are choosing (SHA256) has a great property of being incredibly resistant to collision attacks, it works great for the Schnorr scheme as follows.

We define a signature verification function where:

H'(m, s, e) = H(m || s * G + e * y)
… which is defined to have verified some set of data when H'(m, s, e) = e.

m is the message being signed, s is part 1 of our signature, and e is the hash of our message concatenated with a variable r which is part 2 of our signature.

m, r, s, e, G, y are distributed publicly for users to verify that some user under an asymmetric key pair defined by x, y truly signed a given message m.

To prove that only a user (or users if under attack) who owns such a key pair could possibly create the signature components r, s for message m such that H’(m, s, e) = e, recall that y = x * G :

As s, e and m are already known, the only way to have the conditional statement being e == e being true is that the private key x is known by a user. Q.E.D…?

To sign a message m and derive the signature components r and s, we pick a random scalark to be a seed for our signature scheme.

We operate in the multiplicative group of our curve k times around our generator point G to derive r = k * G. k is what we define to be our residual sum that makes/breaks the whole scheme, as we define:

k = s + e * x ; hence H'(m, s, e) = H(m || k * G) = H(m || r) = e .

Hence, after deriving r, get e = H(m || r) and derive:

and you’ve got your signature (r, s) ready!

In Go, this would be how you’d represent it:

Note however, every single time we sign messages we should always pick a completely new k with a truly random source of information (you could even seed it with H(m || x) given H(x)'s unique pre-image property!).

With k = s + e * x, lets get a set of signatures for two different messages(r0, s0, e0) and (r1, s1, e1).

** note thatron the i'th index is derived from e and s on the i'th index through: r = s * G + e * y .

If k were to be the same for the two messages, denote:

… and hence, if you aren’t careful, with a fixed k you could be leaking the user’s private key x!

One cool thing you could derive out of this equation given the signature components, and message is the user’s public key as well.

This could be one method for verifying a signature by deriving the public key from the signature.

Simply recall that as r = s * G + e * y, we can derive y by:

… which in Go can easily be represented as:

However, a much nicer method to verify a signature would be to see if the multiplicative and additive operations on our elliptic curve group yields the same point positioned as s * G.

This would thus not require us to compute using our expensive hash function two times per verification round.

With signature components someone sends us (r, s), and their public key and plain-text message, we first attain e = H(m || r) and derive:

… and check if the derived s * G from r is equivalent to purely calculating s * G . Remember, the only way s * G would match is if the components (r, s) derived using the asymmetric key pair (x, y) truly belonged and was only known by a particular person.

Otherwise, the trapdoor function would not be fulfilled and hence the scheme remains secure.

Now, in Go…

… and now our Schnorr scheme is ready for whatever! Better distributed DAG pruning operations perhaps.

What’s awesome about this was that it was achieved all through some high school algebra (which gets hindered a bit by elliptic curve group operations).

Here’s a little test case I made with a nice helper print function:

Now, when it comes towards applications of utilizing Schnorr as a form of partial group/threshold signatures (ring signatures) in all kinds of fun decentralized applications, it is relatively easily to implement.

Though, I would like to leave that as an exercise to you.

Feel free to read up on some more of the math here: https://www.deadalnix.me/2017/02/17/schnorr-signatures-for-not-so-dummies/

Enjoy :). If you want the source code up on Github, let me know.

Also, Read

Get Best Software Deals Directly In Your Inbox

--

--