Why Can’t I Use My ID As My Public Key?

Meet Crypto Pairing and Identity Based Encryption (IBE)

Why Can’t I Use My ID As My Public Key?

Meet Crypto Pairing and Identity Based Encryption (IBE)

Pair-based cryptography can do no wrong just now, and is often at the core of many of the current advances in privacy, zero-knowledge proof and multi-party computation. You will find it in signature aggregation — and where we can take many signers and create a single signature from their public keys — and in privacy-preserving methods.

Identity-based Encryption (IBE) is an alternative to PKI, and involves generating the encryption key from a piece of identity for the recipient. For example we could use the email address of the recipient to generate the key for a destination.

For this we have some shared parameters with a trust center that both Bob and Alice trust. If Alice wants to send Bob an email, she takes the parameters from the trust center, and then uses Bob’s email address to generate his public key:

When Bob receives the encrypted email, he contacts the trust center and the center generates the private key required to decrypt the email.

Crypto pairing

So you might read some fairly complicated research papers and even have a look at the Wikipedia page [here], but you probably still can’t make much sense of them. If this is so, then let’s develop a bit of code that illustrates the core concept of pair-based cryptography (bi-linearity and commutative properties).

With the pairing we have two cyclic groups (G1 and G2), and which are of an order of a prime number (n). A pairing on (G1,G2,GT) defines the function e:GG2→GT, and where g1 is the generator for G1 and g2 is the generator for G2. If we have the points of U1 and U2 on G1 and V1 and V2 on G2, we get the bi-linear mapping of:

e(U1+U2,V1)=e(U1,V1)×e(U2,V1)

e(U1,V1+V2)=e(U1,V1)×e(U1,V2)

If U is a point on G1, and V is a point on G2, we get:

e(aU,bV)=e(U,V)^{ab}

If G1and G2 are the same group, we get a symmetric grouping (G1=G2=G), and the following commutative property will apply:

e(U^a,V^b)=e(U^b,V^a)=e(U,V)^{ab}=e(V,U)^{ab}

The computation of e should be efficient in computation time.

The basic steps are:

  1. Alice gets Bob’s ID (Qid). Normally this would be something like the hash of Bob’s email address.
  2. The trust server then selects a secret (s) and creates a public key of sU, and where U is a point on the curve. Alice will receive sU in order to send to Bob.
  3. Alice then selects a random value (r) and creates a pairing of e(sU,Qid)^r. She use this to encrypt the symmetric key she will use for the encrypted message.
  4. Bob uses a private key of sQid and generates the same key with e(rU,sQid). He uses this to decrypt the encrypted key.

Neither Bob nor Alice knows the secret (s) and where only Bob will know the private key for his ID. This will be provided by the trust server.

This works as e(sU,Qid)^r=e(U,sQid)^r=e(rU,sQid)=e(rU,sQid)

The outline coding using the library from the MIRACL library [here] is [here]:

package main
import (
	"fmt"
"github.com/miracl/core/go/core/BN254"
"os"
"strconv"
"math/rand"
"time"
"crypto/sha256"
)
func FP12toByte(F *BN254.FP12) []byte {
	const MFS int = int(BN254.MODBYTES)
var t [12 * MFS]byte
	F.ToBytes(t[:])
return(t[:])
}

func main() {
	BobID:="bob"
s:=31 // Secret server key
	rand.Seed(time.Now().UnixNano())
r:=rand.Intn(4294967296)
	argCount := len(os.Args[1:])
        if (argCount>0) {BobID= (os.Args[1])}
if (argCount>1) {s,_= strconv.Atoi(os.Args[2])}
	h := sha256.New()
h.Write([]byte(BobID))
PbobID := h.Sum(nil)


U := BN254.ECP_generator()
V := BN254.ECP2_generator()
        priv1:=BN254.G1mul(U,BN254.NewBIGint(s))
priv2:=BN254.G2mul(V,BN254.FromBytes(PbobID))
	key_alice := BN254.Ate(priv2,priv1)	 
key_alice = BN254.Fexp(key_alice)
key_alice = BN254.GTpow(key_alice,BN254.NewBIGint(r))
        priv3:=BN254.G1mul(U,BN254.NewBIGint(r))
priv4:=BN254.G2mul(V,BN254.FromBytes(PbobID))
priv4=BN254.G2mul(priv4,BN254.NewBIGint(s))
	key_bob := BN254.Ate(priv4,priv3)	 
key_bob= BN254.Fexp(key_bob)
        fmt.Printf("\nBob ID: %s, Secret: %d, Random: %d\n",BobID,s,r)

        fmt.Printf("\nPairing: %s\n",key_alice.ToString())
fmt.Printf("\nAlice uses key (first 20 bytes):\t0x%x\n",FP12toByte(key_alice)[:20])
fmt.Printf("Bob uses key (first 20 bytes):\t0x%x\n",FP12toByte(key_bob)[:20])

	if key_bob.Equals(key_alice) { fmt.Printf("\nPairing 1 [e(sV,Qid)^r] is equal to Pairing 2 [e(rV,sQid)]")}	
}

A sample run is [here]:

Bob ID: bob@home, Secret: 99, Random: 1964639580
Pairing: [[[1cacae94b91ed2ab6c01d2b90615ffcdb3ddadb0a15ef2534572d75429aa8b9e,03d57facdc2b1192967059846585950d13f16f34aa2a2a957cc84747c4918baa],[212a86b9611493f47895916551c4bfe3d7ea8813b3b83fa55194f99affbdb9a0,0dcb049c002aaebf25af97b1c3c897ddfece7f925655c207ed73d30d08873da4]],[[1f704648268d49a61f3d186352a7ca044b279d2783a22abd143f42b0f95cfa21,18bf82dd579ed56cdc23dccde23b523e10afac5697c4946464ffa38262afa9ec],[1f72aba7c189936b6e10e9e04bdc3a4f3c610c9d99199bdfb64a2a54f8263bcd,2015a1cdb36f86fb593799074e316226d7be5f0eae94ab2f4d8adab7d3ad8f43]],[[0505925d153269cf1f098a98cac61446684cca4ad776694a7d22e18cc322a803,1ff552888960f51e8aafc37f13561c940ec05ed05ea7ce9e1b7b730e66419177],[1cdaf6921edfbba779743484f6a08f7487a03363bfd682e2e82e79c6d68be109,0a5dbc358073682e2c8af23233b8a2051c2c98d93b2f579e18350bcd926cb863]]]
Alice uses key (first 20 bytes):	0x1cacae94b91ed2ab6c01d2b90615ffcdb3ddadb0
Bob uses key (first 20 bytes): 0x1cacae94b91ed2ab6c01d2b90615ffcdb3ddadb0
Pairing 1 [e(sV,Qid)^r] is equal to Pairing 2 [e(rV,sQid)]

Conclusions

I repeat … why can’t I use my email address, or something about my identity as my public key? For just now, we use PKI, but it is a rather cumbersome infrastructure for IoT.