Documentation ¶
Overview ¶
Package keysplitting implements primitives for multi-party RSA signatures using Go's crypto/rsa library
Overview ¶
Keysplitting supports a simple and secure flow for producing multi-party signatures. First, a broker generates an ordinary RSA keypair and splits the private key into shards:
key, _ := rsa.GenerateKey(rand.Reader, 2048) shards, err := keysplitting.SplitD(key, 2, keysplitting.Addition) if err != nil { return err }
The broker then distributes the private shards (as well as the public key) over a secure channel, destroying each shards as it is sent. If the broker will be one of the parties to the signature, it keeps one of the shards.
When it comes time to sign a message, the key shards do not need to be reassembled. Instead, each party uses its shard to generate a partial signature. It is these partial signatures, not the shards, that are combined to create the final valid signature. This can be verified against the public key in the usual way:
err = rsa.VerifyPKCS1v15(&key.PublicKey, crypto.SHA512, hash, fullSig)
The additive vs. multiplicative split schemes ¶
Keysplitting offers two algorithms for splitting the private key, Addition and Multiplication, specified by the SplitBy type. Both methods are equally secure and applicable to most use cases. However, the following differences may lead you to choose one over the other:
- The Multiplication algorithm supports blinding during signature (TODO: not yet implemented)
- The Multiplication algorithm can only be used sequentially (i.e. partial signatures / decryptions are generated one at a time by parties who each have their own shard)
- The Addition algorithm can be used sequentially. Alternatively, all parties can partially sign at once and send the results to a broker, who can combine them without using a key shard
To learn how to use each algorithm, see the examples. To learn more about how they work, see this TODO: detailed explanation published somewhere!!
Sources ¶
[1] https://eprint.iacr.org/2001/060.pdf [2] https://crypto.stanford.edu/semmail/mrsa.pdf
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func SignFirst ¶
func SignFirst(random io.Reader, shard *PrivateKeyShard, hashFn crypto.Hash, hashed []byte) ([]byte, error)
SignFirst uses the given key shard to perform the initial signature on a hashed message. Note that hashed must be the result of hashing the input message using the given hash function
func SignNext ¶
func SignNext(random io.Reader, shard *PrivateKeyShard, hashFn crypto.Hash, hashed []byte, partialSig []byte) ([]byte, error)
SignNext uses the given key shard to sign a partially-signed message
If the original key was split multiplicatively, nextSig(H) <- partialSig(H)^shard (mod N), i.e. a chain of exponentiation
If the original key was split additively, nextSig(H) <- partialSig(H) * H^shard (mod N), i.e. a chain of multiplication
Note that hashed must be the result of hashing the input message using the given hash function.
Types ¶
type PrivateKeyShard ¶ added in v0.4.0
type PrivateKeyShard struct { PublicKey *rsa.PublicKey // public part D *big.Int // split private exponent SplitBy SplitBy // the algorithm used to split the original key }
A PrivateKeyShard represents one shard of a split RSA key. The public key matches that of the whole original key
func DecodePEM ¶ added in v0.3.0
func DecodePEM(encodedPks string) (*PrivateKeyShard, error)
returns key data from a PEM encoding
func SplitD ¶
func SplitD(priv *rsa.PrivateKey, k int, splitBy SplitBy) ([]*PrivateKeyShard, error)
SplitD returns k private key shards that together compose priv.D
If SplitBy.Multiplication is used, the shards will be such that s1 * s2 * ... * sk ≡ D (mod phi(N))
If SplitBy.Addition is used, the shards will be such that s1 + s2 + ... + sk ≡ D (mod phi(N))
func (*PrivateKeyShard) EncodePEM ¶ added in v0.4.0
func (pks *PrivateKeyShard) EncodePEM() (string, error)
returns a PEM encoding of the key data