We can perform some amazing things with crypto pairing. In this case we will take a message (\(M\)), and then generate two public keys (\(W_1\) and \(W_2\)), and then create two signatures (\(SIG_1\) and \(SIG_2\)) from the private keys (\(S_1\) and \(S_2\)). We will add the public keys to create a merged public key (\(W\)) and also add the signatures to produce a merged signature (\(SIG\)). We will then still be able to verify the merged signature with the merged public key. In this case we will use the Miracl Go library. Barreto-Naehrig curves (BN-curves) are elliptic curves that support pairings, with good levels of security and efficiency. BN254 uses two 254-bit elliptic curves (G1 and G2).
Signature Aggregation with BN254 (and Miracl) |
Coding
The coding is here:
package main import "fmt" import "os" import "github.com/miracl/core/go/core" import "github.com/miracl/core/go/core/BN254" func printBinary(array []byte)(s string) { s= "" for i := 0; i < len(array); i++ { s = s+ fmt.Sprintf("%02x", array[i]) } return } func addW(W1 []byte, W2 []byte, W [] byte) (int) { P := BN254.ECP2_fromBytes(W1) Q := BN254.ECP2_fromBytes(W2) P.Add(Q) P.ToBytes(W[:],true) return 0 } func addS(S1 []byte, S2 []byte, S [] byte) (int) { P := BN254.ECP_fromBytes(S1) Q := BN254.ECP_fromBytes(S2) P.Add(Q) P.ToBytes(S[:],true) return 0 } func salt(rng *core.RAND)(IKM [32]byte) { for i:=0;i&li;32;i++ { IKM[i]=byte(rng.GetByte()) } return } func Core_Verify1(SIG []byte, M []byte, W []byte) int { HM := BN254.Bls_hash_to_point(M) D := BN254.ECP_fromBytes(SIG) if !BN254.G1member(D) {return BN254.BLS_FAIL} D.Neg() PK := BN254.ECP2_fromBytes(W) // Use new multi-pairing mechanism r := BN254.Initmp() BN254.Another_pc(r, BN254.G2_TAB, D) BN254.Another(r, PK, HM) v := BN254.Miller(r) v = BN254.Fexp(v) if v.Isunity() { return BN254.BLS_OK } else { return BN254.BLS_FAIL } } func main() { const BGS = BN254.BGS const BFS = BN254.BFS const G1S = BFS + 1 /* Group 1 Size */ const G2S = 2 * BFS + 1 /* Group 2 Size */ var S1 [G1S]byte var W1 [G2S]byte var S2 [G1S]byte var W2 [G2S]byte var W [G2S]byte var SIG [G1S]byte var SIG1 [G1S]byte var SIG2 [G1S]byte var IKM [32]byte rng := core.NewRAND() var raw [100]byte for i := 0; i < 100; i++ { raw[i] = byte(i + 1) } rng.Seed(100, raw[:]) IKM = salt(rng) mess := "This is a test message" argCount := len(os.Args[1:]) if (argCount>0) {mess = string(os.Args[1])} res1 := BN254.Init() if res1 != 0 { fmt.Printf("Failed to Initialize\n") return } res1 = BN254.KeyPairGenerate(IKM[:], S1[:], W1[:]) if res1 != 0 { fmt.Printf("Failed to generate keys\n") return } IKM = salt(rng) res2 := BN254.Init() if res2 != 0 { fmt.Printf("Failed to Initialize\n") return } res2 = BN254.KeyPairGenerate(IKM[:], S2[:], W2[:]) if res2 != 0 { fmt.Printf("Failed to generate keys\n") return } BN254.Core_Sign(SIG1[:], []byte(mess), S1[:]) BN254.Core_Sign(SIG2[:], []byte(mess), S2[:]) addW(W1[:],W2[:],W[:]) addS(SIG1[:],SIG2[:],SIG[:]) fmt.Printf("\nBoneh-Lynn-Shacham BLS signature with aggregation\n") fmt.Printf("Message: %s\n", mess) fmt.Printf("Private key 1: 0x%s\n", printBinary(S1[:])) fmt.Printf("Private key 2: 0x%s\n", printBinary(S2[:])) fmt.Printf("\nPublic key 1: 0x%s\n", printBinary(W1[:])) fmt.Printf("Public key 2: 0x%s\n", printBinary(W2[:])) fmt.Printf("\nSignature 1: 0x%s\n", printBinary(SIG1[:])) fmt.Printf("Signature 2: 0x%s\n", printBinary(SIG2[:])) fmt.Printf("\nMerged public key: 0x%s\n", printBinary(W[:])) fmt.Printf("Merged signarture: 0x%s\n\n", printBinary(SIG[:])) res1 = Core_Verify1(SIG[:], []byte(mess),W[:]) if res1 == 0 { fmt.Printf("Signature is OK\n") } else { fmt.Printf("Signature is *NOT* OK\n") } }
And a sample run:
Boneh-Lynn-Shacham BLS signature with aggregation Message: Hello Private key 1: 0x070e2c5972ccd123d226e4154af268ffe991547770bad5851f8504fe5c8321c300 Private key 2: 0x15eeee5e0798df883c3061e3d5d43ba6058ea2260fdff6b85f06ef500e64e7e900 Public key 1: 0x020f0df48aba4e7b11d8afbf6a2805d79ca9604c8940ab0ff24d092899074ecd641215e6ea01f97405ad6f285c332c6a13496bd456ef41a23278995e2b8aaf0c23 Public key 2: 0x020d58567bf38c4a28477f05caac740211ff9cefe6ad731ffc0331766751d1f8e31bdbf8084cf839fdd91d07e4744bd70c4c11dffd0e1e1d1e0692844c4e19e90a Signature 1: 0x0218106169bd8fbb3b064caf9c0451deece2b5efdf690e5e2d3a6a241645a3e83a Signature 2: 0x020c803ea9279cdda2883bdf5e1eee0d984fcb55ff8fb6f26ac9fc2bfba49a6230 Merged public key: 0x0309d39b921ff8cadee540eaf445292ec771e49933ad7ccb4d19aa17fe25464e3c031e9578c891c7e44590f446c1a6c87da14b4e342dd98f5ecdf9180410afe527 Merged signarture: 0x021972f3b104d6ff59d89a3969a453acbc0ab66bb75b16dd2354035255bbbaf631 Signature is OK