PS Signatures with MIRACL

We just love the magic of crypto pairing, and the opportunity to produce short and randomizable signatures. A signature can then be change…

PS Signatures with MIRACL: Randomizable and Short

We just love the magic of crypto pairing, and the opportunity to produce short and randomizable signatures. A signature can then be change in order to hide the original signature.

One of the best methods around is the PS (Pointcheval Sanders) Short Randomizable Signature and was defined in [1]:

It uses crypto pairs to produce a signature which can be randomized. Initially we have two pairing points (g1 on the G1 curve, and g2 on the G2 curve. The private key is created with two random numbers (x and y):

sk=(x ,y)

and a public key with:

pk=(g2,x g2,y g2)=(g2,X,Y)

To create the signature we take a message (m) and create a random value for the signature (h) and then determine two signature elements:

sig1=h g1

sig2=(x+y×msig1

In this case sig1 and sig2 will be points on G1, and X and Y are points on G2. To check the signature, we have (sig1, pk and sig2) and then equate this pairing:

e(sig1,X+m×Y)=e(sig2,g2)

This works because of the magic of crypto pairing:

e(sig1,X+m×Y)=e(h×g1,x×g2+m×yg2)=

e(h×g1,(x+m×yg2)=e(h×((x+m×y))×g1,g2)=

e(sig2,g1)

To randomize the signature, we just multiply sig2 and sig1 (and which are points on G1) by a random number and can get a new signature, such as:

sig3 = r sig1

sig4 = r sig2

There is no need to reveal the random value (r), and the signature will still check-out.

And, as if by magic we can easily prove the signature. We are currently working with the MIRACL library, so here is an implement of this [here]:

package main

import (
"fmt"
"math/rand"
"time"
"github.com/miracl/core/go/core/BN254"
"github.com/miracl/core/go/core"
"os"

)

func FP12toByte(F *BN254.FP12) []byte {

const MFS int = int(BN254.MODBYTES)
var t [12 * MFS]byte

F.ToBytes(t[:])
return(t[:])
}

func main() {

mymsg:="Hello"

argCount := len(os.Args[1:])

if (argCount>0) {mymsg= (os.Args[1])}

msg:=[]byte(mymsg)

sh:=core.NewHASH256()
for i:=0;i<len(msg);i++ {
sh.Process(msg[i])
}
m:=sh.Hash()

rand.Seed(time.Now().UnixNano())

x:= rand.Intn(4294967296)
y:= rand.Intn(4294967296)
h:= rand.Intn(4294967296)

g1 := BN254.ECP_generator()
g2:= BN254.ECP2_generator()


g:=g2
X:=BN254.G2mul(g2,BN254.NewBIGint(x))
Y:=BN254.G2mul(g2,BN254.NewBIGint(y))

sig1:=BN254.G1mul(g1,BN254.NewBIGint(h))

// (x+y*m)*h
z1:=BN254.G1mul(sig1,BN254.NewBIGint(x)) // xh
z2:=BN254.G1mul(sig1,BN254.FromBytes(m)) // m*h
z2=BN254.G1mul(z2,BN254.NewBIGint(y)) // y*m*h
z1.Add(z2) // (x+y*m)*h
sig2:=z1

X.Add(BN254.G2mul(Y,BN254.FromBytes(m)))

k1 := BN254.Ate(X,sig1)
k1 = BN254.Fexp(k1)

// e(X+M*Y g2,h g1) = e(g2,(x+y*m)h g1)
k2 := BN254.Ate(g,sig2)
k2 = BN254.Fexp(k2)

fmt.Printf("m=%s\nHash=%x\n\n",mymsg,m)

fmt.Printf("Private key:\tx=%d, y=%d\n",x,y)
fmt.Printf("Random value (h):\th=%d\n\n",h)

fmt.Printf("Public key:\tX=%s\nY=%s\n\n",X.ToString(),Y.ToString())

fmt.Printf("Sig1=%s\nSig2=%s\n\n",sig1.ToString(),sig2.ToString())


fmt.Printf("Pair 1 - first 20 bytes:\t0x%x\n",FP12toByte(k1)[:20])
fmt.Printf("Pair 2 - first 20 bytes:\t0x%x\n",FP12toByte(k2)[:20])

if k1.Equals(k2) { fmt.Printf("\nSignatures match")}
}

A sample run with simple values is [here]:

m=hello
Hash=2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
Private key: x=920104504, y=782500753
Random value (h): h=3803832919
Public key: X=([02bc018d7d2f089761d4a9dec8555a941d64b3455289fedd8c20076da6933124,15f0e9cc0182f19eab5b2fd251a92efd4938405d213909741d1aaabaca940ee4],[163c0de0de255e41489e00f4d3cfc781ea68711483d840cc652760a4b99a8cb3,251c48924c0ec9f51a325e5c8300b9664dbf25fde9a964f9621d1794ebccdb83])
Y=([006d423287934b915fec94c31c0fb46f3c422093d351de7b223090d8200b8573,114854ff6b92106023b3980fd0dfe4158b2f19b57b0ed00ba2716f683a16f55c],[0fb4ea51caab7d7cb96d479aaf949aa333bcc95fd5e2d0f27e5833778b719354,1b009b9762a3d7e923b7e0c5484ccc4a1ac1ddd37d855549d11b19329e30068c])
Sig1=(0a157521fd28646277799ad7040694bdca687f207a5ad5d17ee1f8c30dd3e5ec,19fcf52dcabe62d45e3b408a44f91fa5469b547e4da2e75975987ea4ce1e3195)
Sig2=(00c502c089a65ea3a418da468aafd8fa263e81fea90bf60163d0e4718029e0f2,063b457e1b09cfad47b413b16136f0d159d4d72fa254a46acdb6c2388fe08edd)
Pair 1 - first 20 bytes: 0x237de26551d7a283a37a7f4653b0664d48c18a3d
Pair 2 - first 20 bytes: 0x237de26551d7a283a37a7f4653b0664d48c18a3d
Signatures match

Conclusions

The PS signatures are a great step forward, and can be randomized by any entity.

References

[1] David Pointcheval, Olivier Sanders: Short Randomizable Signatures. CT-RSA 2016: 111–126