multi-party-sig

Implementation of protocols for threshold signatures

https://github.com/taurushq-io/multi-party-sig

Science Score: 57.0%

This score indicates how likely this project is to be science-related based on various indicators:

  • CITATION.cff file
    Found CITATION.cff file
  • codemeta.json file
    Found codemeta.json file
  • .zenodo.json file
    Found .zenodo.json file
  • DOI references
    Found 2 DOI reference(s) in README
  • Academic publication links
  • Committers with academic emails
  • Institutional organization owner
  • JOSS paper metadata
  • Scientific vocabulary similarity
    Low similarity (10.4%) to scientific vocabulary

Keywords

cryptography elliptic-curves multi-party-computation signature

Keywords from Contributors

interactive mesh interpretability sequences generic projection optim hacking network-simulation
Last synced: 6 months ago · JSON representation ·

Repository

Implementation of protocols for threshold signatures

Basic Info
  • Host: GitHub
  • Owner: taurushq-io
  • License: apache-2.0
  • Language: Go
  • Default Branch: main
  • Homepage:
  • Size: 2.05 MB
Statistics
  • Stars: 335
  • Watchers: 29
  • Forks: 125
  • Open Issues: 21
  • Releases: 0
Topics
cryptography elliptic-curves multi-party-computation signature
Created about 5 years ago · Last pushed about 1 year ago
Metadata Files
Readme Citation

README.md

multi-party-sig

License

A Go implementation of multi-party threshold signing for:

  • ECDSA, using the "CGGMP" protocol by Canetti et al. for threshold ECDSA signing. We implement both the 4 round "online" and the 7 round "presigning" protocols from the paper. The latter also supports identifiable aborts. Implementation details are also documented in in docs/Threshold.pdf. Our implementation supports ECDSA with secp256k1, with other curves coming in the future. <!-- including with some additions to improve its practical reliability, including the "echo broadcast" from Goldwasser and Lindell. -->

  • Schnorr signatures (as integrated in Bitcoin's Taproot), using the FROST protocol. Because of the linear structure of Schnorr signatures, this protocol is less expensive than CMP. We've also made the necessary adjustments to make our signatures compatible with Taproot's specific point encoding, as specified in BIP-0340.

DISCLAIMER: Use at your own risk, this project needs further testing and auditing to be production-ready.

Features

  • BIP-32 key derivation. Parties can convert their shares of a public key into shares of a child key, as per BIP-32's key derivation spec. Only unhardened derivation is supported, since hardened derivation would require hashing the secret key, which no party has access to.
  • Constant-time arithmetic, via saferith. The CMP protocol requires Paillier encryption, as well as related ZK proofs performing modular arithmetic. We use a constant-time implementation of this arithmetic to mitigate timing-leaks
  • Parallel processing. When possible, we parallelize heavy computation to speed up protocol execution.

Usage

multi-party-sig was designed with the goal of supporting multiple threshold signature schemes. Each protocol can be invoked using one of the following functions:

| Protocol Initialization | Returns | Description | | ------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------- | ------------------------------------------------------------------------------------------- | | cmp.Keygen(group curve.Curve, selfID party.ID, participants []party.ID, threshold int, pl *pool.Pool) | *cmp.Config | Generate a new ECDSA private key shared among all the given participants. | | cmp.Refresh(config *cmp.Config, pl *pool.Pool) | *cmp.Config | Refreshes all shares of an existing ECDSA private key. | | cmp.Sign(config *cmp.Config, signers []party.ID, messageHash []byte, pl *pool.Pool) | *ecdsa.Signature | Generates an ECDSA signature for messageHash. | | cmp.Presign(config *cmp.Config, signers []party.ID, pl *pool.Pool) | *ecdsa.PreSignature | Generates a preprocessed ECDSA signature which does not depend on the message being signed. | | cmp.PresignOnline(config *cmp.Config, preSignature *ecdsa.PreSignature, messageHash []byte, pl *pool.Pool) | *ecdsa.Signature | Combines each party's PreSignature share to create an ECDSA signature for messageHash. | | doerner.Keygen(group curve.Curve, receiver bool, selfID, otherID party.ID, pl *pool.Pool) | *doerner.Config | Generates a new ECDSA private key shared among two participants | | doerner.SignReceiver(config *ConfigReceiver, selfID, otherID party.ID, hash []byte, pl *pool.Pool) | *ecdsa.Signature | Generates a new ECDSA signature for a given message, using the Receiver's config | | doerner.SignSender(config *ConfigSender, selfID, otherID party.ID, hash []byte, pl *pool.Pool) | *ecdsa.Signature | Generates a new ECDSA signature for a given message, using the Sender's config | | frost.Keygen(group curve.Curve, selfID party.ID, participants []party.ID, threshold int) | *frost.Config | Generates a new Schnorr private key shared among all the given participants. | | frost.KeygenTaproot(selfID party.ID, participants []party.ID, threshold int) | *frost.TaprootConfig | Generates a new Taproot compatible private key shared among all the given participants. | | frost.Sign(config *frost.Config, signers []party.ID, messageHash []byte) | *frost.Signature | Generates a Schnorr signature for messageHash. | | frost.SignTaproot(config *frost.TaprootConfig, signers []party.ID, messageHash []byte) | *taproot.Signature | Generates a Taproot compatibe Schnorr signature for messageHash. |

In general, Keygen and Refresh protocols return a Config struct which contains a single key share, as well as the other participants' public key shares, and the full signing public key. The remaining arguments should be chosen as follows:

  • party.ID aliases a string and should uniquely identify each participant in the protocol.
  • curve.Curve represents the cryptogrpahic group over which the protocol is defined. Currently, the only option is curve.Secp256k1.
  • *pool.Pool can be used to paralelize certain operations during the protocol execution. This parameter may be nil, in which case the protocol will be run over a single thread. A new pool.Pool can be created with pl := pool.NewPool(numberOfThreads), and should be freed once the protocol has finished executing by calling pl.Teardown().
  • threshold defines the maximum number of participants which may be corrupted at any given time. Generating a signature therefore requires threshold+1 participants.
  • *ecdsa.PreSignature represents a preprocessed signature share which can be generated before the message to be signed is known. When the message does become available, the signature can be generated in a single round.

Each of the above protocols can be executed by creating a protocol.Handler object. For example, we can generate a new ECDSA key as follows:

```go var ( // sessionID should be agreed upon beforehand, and must be unique among all protocol executions. // Alternatively, a counter may be used, which must be incremented after before every protocol start. sessionID []byte // group defines the cryptographic group over which group := curve.Secp256k1{} participants := []party.ID{"a", "b", "c", "d", "e"} selfID := participants[0] // we run the protocol as "a" threshold := 3 // 4 or more participants are required to generate a signature )

pl := pool.NewPool(0) // use the maximum number of threads. defer pl.Teardown() // destroy the pool once the protocol is done.

handler, err := protocol.NewMultiHandler(cmp.Keygen(group, selfID, participants, threshold, pl), sessionID) if err != nil { // the handler was not able to start the protocol, most likely due to incorrect configuration. } ```

More examples of how to create handlers for various protocols can be found in /example. Note that for two-party protocols like Doerner, a protocol.TwoPartyHandler should be created instead, to manage the back and forth messages required.

After the handler has been created, the user can start a loop for incoming/outgoing messages. Messages for other parties can be obtained by querying the channel returned by handler.Listen(). If the channel is closed, then the user can assume the protocol has finished.

```go func runProtocol(handler *protocol.Handler) { // Message handling loop for { select {

// Message to be sent to other participants
case msgOut, ok := <-handler.Listen():
  // a closed channel indicates that the protocol has finished executing
  if !ok {
    return
  }
  if msgOut.Broadcast {
    // ensure this message is reliably broadcast
  }
  for _, id := range participants {
    if msgOut.IsFor(id) {
      // send the message to `id`
    }
  }

// Incoming message
case msgIn := <- Receive():
  if !handler.CanAccept(msg) {
    // basic header validation failed, the message may be intended for a different protocol execution.
    continue
  }
  handler.Update(msgIn)
}

} }

// runProtocol blocks until the protocol succeeds or aborts runProtocol(handler)

// obtain the final result, or a possible error result, err := handler.Result() protocolError := protocol.Error{} if errors.As(err, protocolError) { // get the list of culprits by calling protocolError.Culprits } // if the error is nil, then we can cast the result to the expected return type config := result.(*cmp.Config) ```

If an error has occurred, it will be returned as a protocol.Error, which may contain information on the responsible participants, if possible.

When the protocol successfully completes, the result must be cast to the appropriate type.

Network

Most messages returned by the protocol can be transmitted through a point-to-point network guaranteeing authentication, integrity and confidentiality. The user is responsible for delivering the message to all participants for which Message.IsFor(recipient) returns true.

Some messages however require a reliable broadcast channel, which guarantees that all participants agree on which messages were sent. These messages will have their Message.Broadcast field set to true. The protocol.Handler performs an additional check due to Goldwasser & Lindell, which ensures that the protocol aborts when some participants incorrectly broadcast these types of messages. Unfortunately, identifying the culprits in this case requires external assumption which cannot be handled by this library.

Known Issues

Intellectual property

This code is copyright (c) Adrian Hamelink and Taurus SA, 2021, and under Apache 2.0 license.

On potential patents: the company that sponsored the development of the CMP protocol stated that it "will not be applying for patents on this technology."

Owner

  • Name: taurushq.io
  • Login: taurushq-io
  • Kind: organization
  • Location: Switzerland

Taurus SA opensource resources

Citation (CITATION.cff)

cff-version: 1.2.0
message: "If you use this software in your research, please cite it as below."
authors:
- family-names: "Hamelink"
  given-names: "Adrian"
  affiliation: "Taurus SA"
- family-names: "Meier"
  given-names: "Lúcás Críostóir"
  affiliation: "Taurus SA"
- family-names: "Aumasson"
  given-names: "J.-P."
  affiliation: "Taurus SA"
title: "multi-party-sig"
version: "v0.3.0-alpha-2021-08-09"
date-released: "2021-06-12"
url: "https://github.com/taurusgroup/multi-party-sig"

GitHub Events

Total
  • Issues event: 2
  • Watch event: 33
  • Issue comment event: 5
  • Push event: 1
  • Pull request review event: 1
  • Pull request event: 13
  • Fork event: 11
  • Create event: 2
Last Year
  • Issues event: 2
  • Watch event: 33
  • Issue comment event: 5
  • Push event: 1
  • Pull request review event: 1
  • Pull request event: 13
  • Fork event: 11
  • Create event: 2

Committers

Last synced: 9 months ago

All Time
  • Total Commits: 579
  • Total Committers: 10
  • Avg Commits per committer: 57.9
  • Development Distribution Score (DDS): 0.444
Past Year
  • Commits: 2
  • Committers: 2
  • Avg Commits per committer: 1.0
  • Development Distribution Score (DDS): 0.5
Top Committers
Name Email Commits
Lúcás Críostóir Meier c****y@g****m 322
Adrian Hamelink a****k@g****m 238
JP Aumasson j****a@p****e 7
zzyalbert z****t@1****m 2
nick y****1@g****m 2
kbreik-nydig 8****g 2
dependabot[bot] 4****] 2
JPA jp@p****e 2
Aviv Frenkel a****v@a****o 1
JP Aumasson jp@t****m 1
Committer Domains (Top 20 + Academic)

Issues and Pull Requests

Last synced: 6 months ago

All Time
  • Total issues: 49
  • Total pull requests: 82
  • Average time to close issues: 29 days
  • Average time to close pull requests: 26 days
  • Total issue authors: 19
  • Total pull request authors: 20
  • Average comments per issue: 0.63
  • Average comments per pull request: 0.29
  • Merged pull requests: 57
  • Bot issues: 0
  • Bot pull requests: 3
Past Year
  • Issues: 2
  • Pull requests: 11
  • Average time to close issues: N/A
  • Average time to close pull requests: 3 days
  • Issue authors: 2
  • Pull request authors: 6
  • Average comments per issue: 0.0
  • Average comments per pull request: 0.0
  • Merged pull requests: 2
  • Bot issues: 0
  • Bot pull requests: 0
Top Authors
Issue Authors
  • cronokirby (25)
  • frenkel26 (2)
  • lucky1024 (2)
  • ThantZin-develope (2)
  • johnthethird (2)
  • valli0x (2)
  • adr1anh (2)
  • Fethbita (1)
  • codyborn (1)
  • SphereDonout (1)
  • Konubinix (1)
  • lianghuiqiang9 (1)
  • tmpfs (1)
  • masterEye-07 (1)
  • chris-wood (1)
Pull Request Authors
  • cronokirby (29)
  • adr1anh (19)
  • mvanmeerbeck (4)
  • kbreik-nydig (4)
  • zzyalbert (3)
  • Konubinix (3)
  • valli0x (3)
  • dependabot[bot] (3)
  • mpetrun5 (2)
  • veorq (2)
  • tmpfs (1)
  • duyquang-axie (1)
  • asdfsx (1)
  • nsquare3 (1)
  • jonathanMweiss (1)
Top Labels
Issue Labels
enhancement (16) bug (5) spec (3) theoretically concerning (2) performance (2) documentation (1) elusive (1)
Pull Request Labels
dependencies (3)

Packages

  • Total packages: 1
  • Total downloads: unknown
  • Total dependent packages: 0
  • Total dependent repositories: 0
  • Total versions: 8
proxy.golang.org: github.com/taurushq-io/multi-party-sig
  • Versions: 8
  • Dependent Packages: 0
  • Dependent Repositories: 0
Rankings
Dependent packages count: 6.3%
Average: 6.5%
Dependent repos count: 6.8%
Last synced: 6 months ago

Dependencies

go.mod go
  • github.com/cronokirby/safenum v0.29.0
  • github.com/davecgh/go-spew v1.1.1
  • github.com/decred/dcrd/dcrec/secp256k1/v3 v3.0.0
  • github.com/fxamacker/cbor/v2 v2.3.0
  • github.com/rs/zerolog v1.23.0
  • github.com/stretchr/testify v1.7.0
  • github.com/zeebo/blake3 v0.2.0
  • golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
  • golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
  • golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55
  • gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
go.sum go
  • github.com/coreos/go-systemd/v22 v22.3.2
  • github.com/cronokirby/safenum v0.29.0
  • github.com/davecgh/go-spew v1.1.0
  • github.com/davecgh/go-spew v1.1.1
  • github.com/decred/dcrd/chaincfg/chainhash v1.0.2
  • github.com/decred/dcrd/crypto/blake256 v1.0.0
  • github.com/decred/dcrd/dcrec/secp256k1/v3 v3.0.0
  • github.com/fxamacker/cbor/v2 v2.3.0
  • github.com/godbus/dbus/v5 v5.0.4
  • github.com/kr/pretty v0.2.1
  • github.com/kr/pty v1.1.1
  • github.com/kr/text v0.1.0
  • github.com/pkg/errors v0.9.1
  • github.com/pmezard/go-difflib v1.0.0
  • github.com/rs/xid v1.2.1
  • github.com/rs/zerolog v1.23.0
  • github.com/stretchr/objx v0.1.0
  • github.com/stretchr/testify v1.7.0
  • github.com/x448/float16 v0.8.4
  • github.com/yuin/goldmark v1.2.1
  • github.com/zeebo/assert v1.1.0
  • github.com/zeebo/blake3 v0.2.0
  • github.com/zeebo/pcg v1.0.0
  • golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2
  • golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
  • golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
  • golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
  • golang.org/x/mod v0.3.0
  • golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3
  • golang.org/x/net v0.0.0-20190620200207-3b0461eec859
  • golang.org/x/net v0.0.0-20201021035429-f5854403a974
  • golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
  • golang.org/x/sync v0.0.0-20190423024810-112230192c58
  • golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9
  • golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
  • golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a
  • golang.org/x/sys v0.0.0-20190412213103-97732733099d
  • golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f
  • golang.org/x/sys v0.0.0-20201014080544-cc95f250f6bc
  • golang.org/x/sys v0.0.0-20201119102817-f84b799fce68
  • golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4
  • golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1
  • golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55
  • golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1
  • golang.org/x/text v0.3.0
  • golang.org/x/text v0.3.3
  • golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e
  • golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e
  • golang.org/x/tools v0.1.0
  • golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7
  • golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898
  • golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
  • gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405
  • gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
  • gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c