The DKLS (Doerner, Kondi, Lee, and Shelat) method [1] implements an ECDSA signing algorithm using threshold protocols. In this case, Bob and Alice will communicate using a DKG method, and then Bob will be able to create a valid signature. We can use the Kryptology library developed by Coinbase to implement 2-of-2 threshold ECDSA signing algorithm of the DKLS method. Once Bob and Alice have communicated, Bob will hold a signature for the message. We will then check this signature for its validity.
2-of-2 threshold ECDSA signing algorithm of DKLS using Kryptology |
Background
The DKLS [Doerner, Kondi, Lee, and Shelat) method [1] implements an ECDSA signing algorithm using threshold protocols. In this case, Bob and Alice will communicate using a DKG method, and then Bob will be able to create a valid signature. We can use the Kryptology library developed by Coinbase to implement 2-of-2 threshold ECDSA signing algorithm of the DKLS method. Once Bob and Alice have communicated, Bob will hold a signature for the message. We will then check this signature for its validity.
Coding
We can use the Kryptology library developed by Coinbase to implement 2-of-2 threshold ECDSA signing algorithm of the DKLS method. Once Bob and Alice have communicated, Bob will hold a signature for the message. We will then check this signature for its validity.
package main import ( "crypto/ecdsa" "crypto/sha256" "fmt" "os" "github.com/btcsuite/btcd/btcec" "github.com/coinbase/kryptology/pkg/core/curves" "github.com/dustinxie/ecc" "github.com/coinbase/kryptology/pkg/tecdsa/dkls" ) func main() { msg := "Hello 123" argCount := len(os.Args[1:]) if argCount > 0 { msg = os.Args[1] } params, _ := dkls.NewParams(btcec.S256(), curves.NewK256Scalar()) alice := dkls.NewAlice(params) bob := dkls.NewBob(params) m := []byte(msg) digest := sha256.Sum256(m) alicePipe, bobPipe := dkls.NewPipeWrappers() errors := make(chan error, 2) go func() { errors <- alice.DKG(alicePipe) }() go func() { errors <- bob.DKG(bobPipe) }() for i := 0; i < 2; i++ { if err := <-errors; err != nil { fmt.Printf("Here") } } fmt.Printf("Message to sign: %s\n", msg) fmt.Printf("\nAlice Secret Key: %x\n", alice.SkA.Bytes()) fmt.Printf("Alice Public Key: %x\n", alice.Pk.Bytes()) fmt.Printf("\nBob Secret Key: %x\n", bob.SkB.Bytes()) fmt.Printf("Bob Public Key: %x\n", bob.Pk.Bytes()) errors = make(chan error, 2) go func() { errors <- alice.Sign(digest[:], alicePipe) }() go func() { errors <- bob.Sign(digest[:], bobPipe) }() for i := 0; i < 2; i++ { if err := <-errors; err != nil { fmt.Printf("Signing failed!!!") } } fmt.Printf("Bob Signature: R:%x S:%x\n", bob.Sig.R, bob.Sig.S) fmt.Printf("\n=== Now checking with Bob's public key ===\n") publicKey := ecdsa.PublicKey{ Curve: ecc.P256k1(), //secp256k1 X: bob.Pk.X, Y: bob.Pk.Y, } rtn := ecdsa.Verify(&publicKey, digest[:], bob.Sig.R, bob.Sig.S) if rtn { fmt.Printf("Signature works. Yipee!") } else { fmt.Printf("Signature does not check out!!!") } }
Initally, we split the secret key into two shares and distribute these to Bob and Alice., and which are stored as bob.SkA and alice.SkB. These will be used to generate a public key that Bob and Alice can use (bob.Pk and alice.Pk). This public key can be used to verify the generated digital signature. The following displays the secret shares and the public key:
fmt.Printf("Message to sign: %s\n", msg) fmt.Printf("\nAlice Secret Key: %x\n", alice.SkA.Bytes()) fmt.Printf("Alice Public Key: %x\n", alice.Pk.Bytes()) fmt.Printf("\nBob Secret Key: %x\n", bob.SkB.Bytes()) fmt.Printf("Bob Public Key: %x\n", bob.Pk.Bytes())
Bob generates a signature by communicating with Alice through DKG, and where the generated signature has two values: R and S. This is displayed as:
fmt.Printf("Bob Signature: R:%x S:%x\n", bob.Sig.R, bob.Sig.S)
We can then take Bob's public key (bob.Pk.X and bob.Pk.Y), and then check that this signature is the valid against the public key:
fmt.Printf("\n=== Now checking with Bob's public key ===\n") publicKey := ecdsa.PublicKey{ Curve: ecc.P256k1(), //secp256k1 X: bob.Pk.X, Y: bob.Pk.Y, } rtn := ecdsa.Verify(&publicKey, digest[:], bob.Sig.R, bob.Sig.S) if rtn { fmt.Printf("Signature works. Yipee!") } else { fmt.Printf("Signature does not check out!!!") }
A sample run:
Message to sign: hello 123 Alice Secret Key: 4d8774e7588a7af7886f1d97216bd7cf97bcce0f3ed4b0cc1308eba19d7068ce Alice Public Key: 8383eb0260d211043e190b4b8a79db1a95ac0f9b6b5e37946e4bf76f4ad733535ccf8a8e48632107b58f8311f1df1580cbfdd80db01ae952435b4897ecf586ef Bob Secret Key: d099fd0419dc6afb58229ceece9308a89f35d574e6077ccdf41c50b0ce48c0d0 Bob Public Key: 8383eb0260d211043e190b4b8a79db1a95ac0f9b6b5e37946e4bf76f4ad733535ccf8a8e48632107b58f8311f1df1580cbfdd80db01ae952435b4897ecf586ef Bob Signature: R:bb4c4b4fbba9da07687320e0c2bf95e5eef5471db1b819fd0188b14f4a60362c S:1efc7288269e613e05faaa29370f86b46cf57cb107e41ef3030a4d345dd0a911 === Now checking with Bob's public key === Signature works. Yipee!
Coding
Reference
[1] Doerner, J., Kondi, Y., Lee, E., & Shelat, A. (2019, May). Threshold ECDSA from ECDSA assumptions: the multiparty case. In 2019 IEEE Symposium on Security and Privacy (SP) (pp. 1051-1066). IEEE.