Go and Link Some Ring Signatures

A demo of the method is [demo].

Go and Link Some Ring Signatures

A demo of the method is [demo].

A ring signature is a digital signature that is created by a member of a group which each have their own keys. It is then not be possible to determine the person in the group who has created the signature. A ring signature provides anonymity, unforgivably and collusion resistance. The method was initially created by Ron Rivest, Adi Shamir, and Yael Tauman in 2001, and in their paper they proposed the White house leak dilemma.

In a ring signature we define a group of entities who each have their own public/private key pairs of (P1, S1), (P2, S2), …, (Pn, Sn). If we want an entity i to sign a message (message), they use their own secret key (si), but the public keys of the others in the group (m,si,P1…Pn). It should then be possible to check the validity of the group by knowing the public key of the group, but not possible to determine a valid signature if there is no knowledge of the private keys within the group.

So let’s say that Trent, Bob, Eve and Alice are in a group, and they each have their own public and secret keys. Bob now wants to sign a message from the group. He initially generates a random value v, and then generates random values (xi) for each of the other participants, but takes his own secret key (si) and uses it to determine a different secret key, and which reverse of the encryption function. He now takes the message and takes a hash of it, and thus creates a key (k). This key will be used with symmetric encryption to encrypt each of the elements of the ring (Ek), and then each element of the ring uses an EX-OR function from the previous element (Figure 1).

Each of the random values for the other participants are then encrypted with the public key of the given participant. Bob then computes the value of ys in order to create the ring (the result of the ring must equal v). He will then inverse this value to produce the equivalent private key (xs). Bob now releases the overall signature, and the random x values, along with the computed secret key. To check the signature, the receive just computes the ring, and checks that the result matches the sent signature.

Within a blockchain environment we can gather a number of users into a group, and then use a ring signature to keep anonymity. It will then be extremely difficult to tell which of the users in the group signed for the transaction, especially if the users have the same levels of transactions.

Linkable ring signatures

A linkable ring signature allows one person in the group to sign on behalf of the group, but has the addition of a tag so that an external verifier can know that the signature has been produced by a defined signer, but where they cannot tell who the signer is. The linkable ring signature method is used within the Monero cryptocurrency and defined by the Ring Confidential Transaction (RingCT).

In the case below, Bob adds a tag to the signature, and where Victor, if he knew the tag could see that it was Bob who signed for it. Victor and Bob use a stealth address (more information is defined here), which allows Victor to determine the privacy key for the public key that Bob has used to sign onto the ring. The smart contract then just matches the signatures of this private key, and will sign from the ring to Victor’s new address.

The following defines some code [taken from here][demo]:

package main
import (
"strconv"
    "os"
"fmt"
"encoding/hex"
"go.dedis.ch/kyber"
"go.dedis.ch/kyber/group/edwards25519"

    "go.dedis.ch/kyber/sign/anon"
)

func main() {
    m:="Hello"
scope :="My Link"
n:=4
    argCount := len(os.Args[1:])
        if (argCount>0) {m= string(os.Args[1])}
if (argCount>1) {n,_= strconv.Atoi(os.Args[2])}
if (argCount>2) {scope= string(os.Args[3])}
    S := []byte(scope) // scope for linkage tags
    M := []byte(m) 
    suite :=  edwards25519.NewBlakeSHA256Ed25519()

    rand := suite.RandomStream()
    // Create an anonymity set of random "public keys"
X := make([]kyber.Point, n)
for i := range X { // pick random points
X[i] = suite.Point().Pick(rand)
}
    fmt.Printf("Message: %s\nLinkable address: %s\n\n",M,S)
fmt.Printf("Public keys: %s\n\n",X)
    // Make two actual public/private keypairs (X[mine],x)
mine1 := 1 // only the signer knows this
mine2 := 2
    x1 := suite.Scalar().Pick(rand) // create a private key x
x2 := suite.Scalar().Pick(rand)
    X[mine1] = suite.Point().Mul(x1, nil) // corresponding public key X
X[mine2] = suite.Point().Mul(x2, nil)
    fmt.Printf("Private key of signer: %s\n\n",x1)
fmt.Printf("Public key of signer: %s\n\n",X[1])
    // Generate two signatures using x1 and two using x2

    var sig [4][]byte
    sig[0] = anon.Sign(suite, M, anon.Set(X), S, mine1, x1)
sig[1] = anon.Sign(suite, M, anon.Set(X), S, mine1, x1)
sig[2] = anon.Sign(suite, M, anon.Set(X), S, mine2, x2)
sig[3] = anon.Sign(suite, M, anon.Set(X), S, mine2, x2)
for i := range sig {
fmt.Printf("Signature %d:\n%s", i, hex.Dump(sig[i]))
}
    // Verify the signatures against the correct message
var tag [4][]byte
for i := range sig {
goodtag, err := anon.Verify(suite, M, anon.Set(X), S, sig[i])
if err != nil {
panic(err.Error())
}
tag[i] = goodtag
if tag[i] == nil || len(tag[i]) != suite.PointLen() {
panic("Verify returned invalid tag")
}
fmt.Printf("Sig%d tag: %s\n", i,
hex.EncodeToString(tag[i]))
}
}

A sample run is give below. The first two signatures are signed by the main signer [demo]:

Message: Testing 123
Linkable address: Bill Link
Public keys: [77b9dfd5c322dacb5f3dc1db7c36180082bf136c4bafb3e43be35f60c38f6706 771bc6f4e6746bc4717ded897f1f5400ab30a0e4747e8fd16c4ed5d22c117eba 3562643ee167258346412eaa4bfdfdeda21327dcf3301243bce3876d453f9ebd 49bdb0f94969988a7289f49fdaf39a1129fa3c3d0dc0f3cb7d958c9fb33155b1]
Private key of signer: edc7878a45071d19559932b0ea9b495474f40bfa734dc451aaeffbc3c1260904
Public key of signer: 387b1d3a244c8842458b64fd7723c73e8db53e65028c3fea2a0467601a650170
Signature 0 (first 30 hex): 8373b73cc1cd72121d561c3b7c699f2eee615ae10d11bb6a56315e738389
Signature 1 (first 30 hex): 8f0357d38adfe3761f3cbe9ba0dc86f51d6ea671eba03856edc8e505f0fe
Signature 2 (first 30 hex): 7199afa0b9115bfcc5ba729c6dfb8848c3678639f5b65a9780f4cd736948
Signature 3 (first 30 hex): c3901fbcb2fc92bceb0218f688df142ce14c73ecf69cfbe99d462a444ab3
Sig0 tag: 8fd2bee76761ed17515a3ad2311aeb5b6c183f7babb5cd3b2ce34a19e68174e1
Sig1 tag: 8fd2bee76761ed17515a3ad2311aeb5b6c183f7babb5cd3b2ce34a19e68174e1
Sig2 tag: 3551ad8a5cf20b5e1558eec57b6a8b326d5e139175b12e56dda2d035ba55edb7
Sig3 tag: 3551ad8a5cf20b5e1558eec57b6a8b326d5e139175b12e56dda2d035ba55edb7

Ring signatures and the mixing contract

Within an anonymised infrastructure, we can create a stealth address which is a one time address for a transaction. This can generate a key pair for the transaction and then perform the transaction.

Linkable ring signatures can then be used with stealth addresses to create mixing contract, and which has this operation:

  1. A contract is created to verify ring signatures, receive and distribute cryptocurrency. This contract define the minimum number of users that are required to enter into the contract. There will be a number of senders and which link to a number of recipients.
  2. Each sender generates a new key pair and then sends the public key to the recipient it wants to receive funds. They then generate a shared secret key (the stealth address — more details on these here). The sender then sends its newly created public key to the contract.
  3. The contract then waits for enough senders to participate in the contract. When this happens, it will have a list of the public keys for all the senders.
  4. Each recipient will then remember the public key of its sender, and map the secret key that is associated with it.
  5. The recipient then sends a signature to the contract, along with a tag.
  6. The contract will then match the tag to one of the public keys that it has, and then release the funds to the recipient.

Conclusions

Within linked ring signatures we can add a tag, and then use this with a stealth address for the one-time transaction mapping to happen. This is the way that Monero hides the details of a transaction.