BN256 SignaturesElliptic curves are used fairly extensively in public key encryption (such as in Bitcoin and Tor). A BN-curve (Barreto-Naehrig curve) [2] defines an elliptic curve which can be used for pairings that allow for a high security and efficiency level. This page uses pairings over a 256-bit BN curve and derives a signature for a message. The curve is defined by \(y^2 = x^3 + a.x + b \pmod p\). They can be used to implement pairing-based cryptography. In this case, we will have a key pairs of (\(sk,pk\)) and which will produce a signature of \(\sigma\). |
Method
With BN256, we create the private key from a random number. This is a private key value (\(sk\)) and a public key mapped to the G2 curve::
\(pk=sk.G_2\)
This is implemented as:
privKey, _, _ := bn256.RandomG2(rand.Reader) G2 := new(bn256.G2).ScalarBaseMult(big.NewInt(1)) pubKey := new(bn256.G2).ScalarBaseMult(privKey)
Next we create a hash of the message (\(h(M)\)) and then create the signature of:
\(\sigma=sk.H(M)\)
This is implemented as:
hash := bn256.HashG1(msg, salt) sigma := hash.ScalarMult(hash, privKey)
Next we check the pair:
\( e(\sigma, G_2) == e(H(m), pk )\)
and implemented as
h := bn256.HashG1(msg, salt) lhs := bn256.Pair(sigma, G2) rhs := bn256.Pair(h, pubKey)
This works because:
\( e(\sigma, G_2) == e(H(m), pk )\)
is:
\( e(sk.H(M), G_2) == e(H(m), pk )\)
and:
\( e(H(M), sk.G_2) == e(H(m), pk )\)
which is:
\( e(H(M), pk) == e(H(m), pk )\)
If lhs is equal to rhs, the pairing works, and the signature is verified.
Coding
We can use the Go programming language to implement compiled code for cryptography.
An outline of the Go code is:
package main import ( "bytes" "fmt" "math/big" "crypto/rand" "os" "github.com/cloudflare/bn256" ) func main() { salt := []byte{11, 12, 13, 14} message:="hello" argCount := len(os.Args[1:]) if argCount > 0 { message = os.Args[1] } msg := []byte(message) G2 := new(bn256.G2).ScalarBaseMult(big.NewInt(1)) privKey, _, _ := bn256.RandomG2(rand.Reader) pubKey := new(bn256.G2).ScalarBaseMult(privKey) hash := bn256.HashG1(msg, salt) sigma := hash.ScalarMult(hash, privKey) // check e(sigma, g2) == e(H(m), pk ) h := bn256.HashG1(msg, salt) rhs := bn256.Pair(h, pubKey) lhs := bn256.Pair(sigma, G2) fmt.Printf("Message: %s\n", message) fmt.Printf("Private key: %x\n", privKey) fmt.Printf("\nPublic key: %s\n", pubKey) fmt.Printf("\nSignature (sigma): %x\n", sigma.Marshal()) if bytes.Equal(rhs.Marshal(), lhs.Marshal()) { fmt.Printf("\nSignature verified!") } }
A sample run:
Message: hello Private key: 2405330eb49aaccfd4f920931ebe0829284a904afebe3b07a9e0cd379f605f1b Public key: bn256.G2((1fcc63c02358b7bbd19d3c7ebc226300eefb2540386656ea5691a6a3eb0fabd8, 7aed7fd6c19af0626e07b69db2c8d824ef748206d567eeacafeffecff79afba9), (1fb5d45f0804f7b60a1f866199f2c6f4e9efb322958530c2ac218c9565ecd02a, 7baddba87883018a83a26d3f2f5af29ed0592765feeaaf968a8955b6927f6558)) Signature (sigma): 7e94755ecddf2406b4d2906adf5e0e337efa10fb4b21c5ed4c4127fbdcfb02916e983d4df4d4c3e55d4164e62c2fddb723a80e393f6881dcbdac9c487077a115 Signature verified!