\(e(aU,bV) = e(U,V)^{ab} = e(abU, V) = e(U, abV ) = e(bU,aV)\)
In this case we will use Bob and Alice's ID to generate a secret shared key, and use the MIRACL library.
Identity-based (authenticated) key agreement
[MIRACL Home][Home]
With pairing-based cryptography we have two cyclic groups (\(G_1\) and \(G_2\)), and which are of an order of a prime number (\(n\)). A pairing on \((G_1,G_2,G_T)\) defines the function \(e:G_1 \times G_2 \rightarrow G_T\), and where \(g_1\) is a generator for \(G_1\) and \(g_2\) is a generator for \(G_2\). If \(U\) is a point on \(G_1\), and \(V\) is a point on \(G_2\), we have following rules:
\(e(aU,bV) = e(U,V)^{ab} = e(abU, V) = e(U, abV ) = e(bU,aV)\) In this case we will use Bob and Alice's ID to generate a secret shared key, and use the MIRACL library. |
First we have two curves (\(G_1\) and \(G_2\)) and initially we define a large prime number (\(q\)). Initally the KGC (Key Generation Centre) creates a secret random value (\(s\)) and shares it with Bob and Alice. We then have a known ID for Bob (\(ID_{bob}\)) and for Alice (\(ID_{alice}\)). Their public key will then become the hash of these values mapped to a curve:
\(Q_A = H(ID_A)\)
\(Q_B = H(ID_B)\)
The secret key for Alice is then:
\(d_A=s Q_A\)
And the secret key for Bob is then:
\(d_B=s Q_B\)
Now, all Alice has to do to generate a shared key between Bob and Alice is to take Bob public key value \(Q_A = H(ID_A)\) and do a pairing of:
\(e(d_A,Q_B)\)
For Bob it will be:
\(e(d_B,Q_A)\)
And they should end up with the same shared key, as:
\(e(d_A,Q_B) = e(s Q_A,Q_B) = e(Q_A,s Q_B) = e(Q_A,dB) \)
The outline coding using the library from the MIRACL library [here] is
package main import ( "fmt" "github.com/miracl/core/go/core" "github.com/miracl/core/go/core/BN254" "math/rand" "time" "os" ) func FP12toByte(F *BN254.FP12) []byte { const MFS int = int(BN254.MODBYTES) var t [12 * MFS]byte F.ToBytes(t[:]) return(t[:]) } func randval() *core.RAND { s1 := rand.NewSource(time.Now().UnixNano()) r1 := rand.New(s1) rng := core.NewRAND() var raw [100]byte for i := 0; i < 100; i++ { raw[i] = byte(r1.Intn(255)) } rng.Seed(100, raw[:]) return rng } func main() { BobID:="athome" AliceID:="myaddress" argCount := len(os.Args[1:]) if (argCount>0) {BobID= (os.Args[1])} if (argCount>1) {AliceID= os.Args[2]} q := BN254.NewBIGints(BN254.CURVE_Order) s:=BN254.Randomnum(q,randval()) sh:=core.NewHASH256() for i:=0;i < len(BobID);i++ { sh.Process(BobID[i]) } Q_B:=sh.Hash() sh=core.NewHASH256() for i:=0;i < len(AliceID);i++ { sh.Process(AliceID[i]) } Q_A:=sh.Hash() QA := BN254.ECP_mapit(Q_A) // Alice's secret key: dA dA:=BN254.G1mul(QA,s) QB := BN254.ECP2_mapit(Q_B) // Bob's secret key: dB dB:=BN254.G2mul(QB,s) LHS:=BN254.Ate(QB,dA); LHS=BN254.Fexp(LHS) RHS:=BN254.Ate(dB,QA); RHS=BN254.Fexp(RHS) fmt.Printf("Bob ID:\t\t%s\n",BobID) fmt.Printf("Alice ID:\t%s\n\n",AliceID) fmt.Printf("s:\t%s\n\n",s.ToString()) fmt.Printf("QB:\t%s\n\n",QB.ToString()) fmt.Printf("QA:\t%s\n\n",QA.ToString()) fmt.Printf("\n\nPair 1 e(dA,QB) - first 20 bytes:\t0x%x\n",FP12toByte(LHS)[:20]) fmt.Printf("Pair 2 e(dB,QA) - first 20 bytes:\t0x%x\n",FP12toByte(RHS)[:20]) if LHS.Equals(RHS) { fmt.Printf("\nSignature match\n")} }
A sample run is:
Bob ID: bob@home Alice ID: alice@home s: 0c454f6b0119b345489c4452fd58bf80ee24ff36d1f9a3fa1f38995e77161619 QB: ([0e0c27fda99a9cebb9b647a99e3c3821ca7512ba40251577010f3d284ec5dce4,0739f52acb074f77826a1fd05e0ecb44f4e6ad38274f4d691a5ab55e97b15dd0],[0fc2a977d7e1ccfa2c070180855ea532c2c4da3538cda2bdab733c0f26e5e112,030ee76d93b45c313f43e15ddaf2fd301f9ca6ce32b37981d93283ce76ad4f2b]) QA: (12274944c48d83c874fe2fd6f5bac76cb2a9062b0edbcd2d6a7eda4cdc75ccc4,074dc393de05a5d44a979a7645932ebf9c4c6bfc27f6de6e2227163011985426) Pair 1 e(dA,QB) - first 20 bytes: 0x207b6132a395ddbe023574b04bdb691c338a7ff0 Pair 2 e(dB,QA) - first 20 bytes: 0x207b6132a395ddbe023574b04bdb691c338a7ff0 Secret match
MASTER’S THESIS, Pairing-Based Cryptography, Martijn Maas. [link].