RingSig gem for Ruby

Build Status

This gem implements a signature scheme known as one-time ring signatures. The algorithm for one-time ring signatures was originally described in section 4.4 of the CryptoNote Whitepaper.

Ring signatures

Ring signatures are a special type of digital signature that allows the signer to achieve unconditional unlinkability between their signature and their public key. Signers sign a message using their private key and an arbitrary set of foreign public keys. Verifiers are given the full set of public keys that a message was signed with. Verifiers can prove that one of the private keys signed the message, but they cannot determine which private key was actually used for signing.

The signatures produced by this gem are said to be one-time ring signatures, because the signature includes a Key Image, which is the same for all messages signed with the same private key. Therefore, if a signer signs multiple messages with the same private key, the signatures can be linked.

This gem does not use any randomness. All the algorithms are deterministic, and do not require any sort of external source of randomness. When signing, a seed is computed from a hash of the message and the private key. That seed is used along with the hash algorithm and a nonce anywhere the signing algorithm calls for randomness. As a result, the same inputs will always generate the same signature.

Current limitations

  • This gem is not optimized for speed. All elliptical curve arithmetic is computed in pure ruby. As a result, the sign and verify operations are slow. Future versions will hopefully be better optimized for speed.
  • This gem was not written by a cryptography expert. It is provided "as is" and it is the user's responsibility to make sure it will be suitable for the desired purpose.


This library is distributed as a gem named ring_sig at RubyGems.org. To install it, run:

gem install ring_sig



First, require the gem:

require 'ring_sig'

Instantiate a hasher. This specifies the ECDSA::Group, and the hash algorithm that will be used for signing.

hasher = RingSig::Hasher::Secp256k1_Sha256

Create a private key for signing. For our example, we'll just use the private key 1. In the wild, you'll want to utilize a securely generated key.

key = RingSig::PrivateKey.new(1, hasher)

Instantiate a set a foreign public keys for signing. To demonstrate that any arbitrary keys can be used, we'll use the public keys from the coinbase transactions of the first three blocks on the bitcoin blockchain (we can do this since our hasher uses Secp256k1 as its ECDSA::Group).

foreign_keys = %w{
  }.map {|s| RingSig::PublicKey.from_hex(s, hasher) }


Next, we sign the message. This will assign a RingSig::Signature to the sig variable, and a deterministically shuffled Array of RingSig::PublicKeys to the public_keys variable.

sig, public_keys = key.sign("Hello World!", foreign_keys)

You can encode the contents of the signature using the to_hex method:

sig_hex = sig.to_hex


In order to verify the signature, the verifier will need the signature, and the ordered set of public keys.

In order to instantiate a signature object from a hex string, you can use the from_hex method:

sig2 = RingSig::Signature.from_hex(sig_hex, hasher)

Finally, verify the signature:

sig2.verify("Hello World!", public_keys)


The above example signature used Secp256k1 for the ECDSA group, and SHA256 for the hash algorithm. You can specify alternates if you'd like, by using a different hasher:

key = RingSig::PrivateKey.new(1, RingSig::Hasher::Secp384r1_Sha384)

You can also instantiate your own hasher directly, rather than using the pre-defined constants:

hasher = RingSig::Hasher.new(ECDSA::Group::Secp384r1, OpenSSL::Digest::SHA384)

Note that the byte-length of the group's order and the digest method must match, or else the signatures generated will leak the position of the true signer.


There currently aren't any standards around Ring Signatures that I know of. This gem attempts to make sensible choices such that the exact same algorithm can easily be implemented in other languages.

I'd love to see standards emerge around this powerful cryptographic primitive. If you have any feedback about how to make the implementation of the algorithms in this gem more inter-operable with other systems, I'd love to hear it!


To submit a bug, please go to this gem's github page and create a new issue.

If you'd like to contribute code, these are the general steps:

  1. Fork and clone the repository
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -m 'Added some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a Pull Request

Please make sure to write tests for your new code, and follow the existing code standards wherever possible.


Special thanks to the authors of the very excellent ECDSA gem. Not only is it a dependency of this gem, I also used it to gain a much better understanding of elliptical curve crypto, and used it as inspiration for this gem.

Supported platforms

Ruby 1.9.3 and above, including jruby-19mode.


For complete documentation, see the RingSig page on RubyDoc.info.