Within elliptic curves, we can have a scalar value (\(a\)) and a base point on the curve (\(G\)). We then perform an add operation to produce another point on the curve as \(aG\). This is the equivalent operation of adding the point \(G\) for \(a\) times. Normally we would define \(aG\) as a public key point, and \(a\) as a private key scalar value. Typically these operations are done within a finite field defined by prime number (\(p\)). In the case of Curve 25519, this prime number is \(2^{255}-19\). With the Ed25519 curve, we only need one of the co-ordinate points, and so the public key point is the same length as the private key scalar value. With other curves (such as sepc256k1) we will end up with a longer value for our points than the scalar values. The Kryptology library supports a wide range of curves, including BLS (such as BLS 12377), Ed25519, P256, K256 (secp256k1 - as used in Bitcoin and Ethereum) and Pallas. The Boneh–Lynn–Shacham (BLS) signature method produces short signatures and use elliptic curve pairing (and which are also known as bilinear maps). These are particularly useful for Zero-Knowledge Proofs (ZKPs). Ed25519 uses Curve 25519 and is known to be a fast and efficient method for processing elliptic curves operations. In the following we only show the y-coodinate point, as we can easily compute the x-coordinate point from the equation defining the curve. With the ToAffineCompressed() method for a point we just get the \(y\) co-ordinate, while the ToAffineUncompressed() method gives us the \((x,y)\) point.
Determine public key point for ECC with Kryptology |
Implementation
The following is an implementation for the supported curves (Ed25519, BLS 12377, sepc256k1, P256 and Pallas):
package main import ( "fmt" "os" "strconv" "github.com/coinbase/kryptology/pkg/core/curves" ) func main() { val1 := 1 argCount := len(os.Args[1:]) if argCount > 0 { val1, _ = strconv.Atoi(os.Args[1]) } curve := curves.ED25519() x := curve.Scalar.New(val1) G := curve.Point.Generator() xG := curve.Point.Generator().Mul(x) fmt.Printf("x=%x\n", x.Bytes()) fmt.Printf("\n=== ED25519:\n G=%x\n xG=%x\n xG(x,y)=%x\n", G.ToAffineCompressed(), xG.ToAffineCompressed(), xG.ToAffineUncompressed()) fmt.Printf(" x=%x, y=%x\n \n", xG.ToAffineUncompressed()[0:32], xG.ToAffineUncompressed()[32:]) curve = curves.BLS12377G1() x = curve.Scalar.New(val1) G = curve.Point.Generator() xG = curve.Point.Generator().Mul(x) fmt.Printf("\n=== BLS12377G1:\n G=%x\n xG=%x\n xG(x,y)=%x\n", G.ToAffineCompressed(), xG.ToAffineCompressed(), xG.ToAffineUncompressed()) curve = curves.K256() x = curve.Scalar.New(val1) G = curve.Point.Generator() xG = curve.Point.Generator().Mul(x) fmt.Printf(" x=%x, y=%x\n \n", xG.ToAffineUncompressed()[0:32], xG.ToAffineUncompressed()[32:]) fmt.Printf("\n=== Sepc256k1:\n G=%x\n xG=%x\n xG(x,y)=%x\n", G.ToAffineCompressed(), xG.ToAffineCompressed(), xG.ToAffineUncompressed()) fmt.Printf(" x=%x, y=%x\n \n", xG.ToAffineUncompressed()[1:33], xG.ToAffineUncompressed()[33:]) curve = curves.P256() x = curve.Scalar.New(val1) G = curve.Point.Generator() xG = curve.Point.Generator().Mul(x) fmt.Printf("\n=== P256:\n G=%x\n xG=%x\n xG(x,y)=%x\n", G.ToAffineCompressed(), xG.ToAffineCompressed(), xG.ToAffineUncompressed()) fmt.Printf(" x=%x, y=%x\n \n", xG.ToAffineUncompressed()[1:33], xG.ToAffineUncompressed()[33:]) curve = curves.PALLAS() x = curve.Scalar.New(val1) G = curve.Point.Generator() xG = curve.Point.Generator().Mul(x) fmt.Printf("\n=== PALLAS:\n G=%x\n xG=%x\n xG(x,y)=%x\n", G.ToAffineCompressed(), xG.ToAffineCompressed(), xG.ToAffineUncompressed()) }
A sample run:
x=0100000000000000000000000000000000000000000000000000000000000000 === ED25519: G=5866666666666666666666666666666666666666666666666666666666666666 xG=5866666666666666666666666666666666666666666666666666666666666666 xG(x,y)=1ad5258f602d56c9b2a7259560c72c695cdcd6fd31e2a4c0fe536ecdd33669215866666666666666666666666666666666666666666666666666666666666666 x=1ad5258f602d56c9b2a7259560c72c695cdcd6fd31e2a4c0fe536ecdd3366921, y=5866666666666666666666666666666666666666666666666666666666666666 === BLS12377G1: G=a08848defe740a67c8fc6225bf87ff5485951e2caa9d41bb188282c8bd37cb5cd5481512ffcd394eeab9b16eb21be9ef xG=a08848defe740a67c8fc6225bf87ff5485951e2caa9d41bb188282c8bd37cb5cd5481512ffcd394eeab9b16eb21be9ef xG(x,y)=008848defe740a67c8fc6225bf87ff5485951e2caa9d41bb188282c8bd37cb5cd5481512ffcd394eeab9b16eb21be9ef01914a69c5102eff1f674f5d30afeec4bd7fb348ca3e52d96d182ad44fb82305c2fe3d3634a9591afd82de55559c8ea6 === Sepc256k1: G=0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 xG=0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 xG(x,y)=0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 x=79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798, y=483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 === P256: G=036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296 xG=036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296 xG(x,y)=046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5 x=6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296, y=4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5 === PALLAS: G=0100000000000000000000000000000000000000000000000000000000000080 xG=0100000000000000000000000000000000000000000000000000000000000080 xG(x,y)=0100000000000000000000000000000000000000000000000000000000000000bb2aedca237acf1971473d33d45b658f54ee7863f0a9df537c93120aa3b5741b
With secp256k1 we get the following for the base point:
G=0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 xG=0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 xG(x,y)=0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8
The '04' part identifies an \((x,y)\) point, and \(x\)=79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798, \(y\)=483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8. We have 64 hex characters for each coordinate value, and thus we have 256-bit \(x\) and \(y\) values. The full point will thus have 512 bits.