Skip to content

Commit

Permalink
Support DKG
Browse files Browse the repository at this point in the history
  • Loading branch information
azuchi committed Feb 16, 2024
1 parent 07c234b commit b129f03
Show file tree
Hide file tree
Showing 6 changed files with 367 additions and 10 deletions.
64 changes: 64 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,67 @@ sig = FROST.aggregate(commitment_list, msg, group_pubkey, [sig_share1, sig_share
# verify final signature
FROST.verify(sig, group_pubkey, msg)
```

### Using DKG

DKG can be run as below.

```ruby
max_signer = 5
min_signer = 3

secrets = {}
round1_outputs = {}
# Round 1:
# For each participant, perform the first part of the DKG protocol.
1.upto(max_signer) do |i|
polynomial, package = FROST::DKG.part1(i, min_signer, max_signer, group)
secrets[i] = polynomial
round1_outputs[i] = package
end

# Each participant sends their commitments and proof to other participants.
received_package = {}
1.upto(max_signer) do |i|
received_package[i] = round1_outputs.select {|k, _| k != i}.values
end

# Each participant verify knowledge of proof in received package.
received_package.each do |id, packages|
packages.each do |package|
expect(FROST::DKG.verify_proof_of_knowledge(package)).to be true
end
end

# Round 2:
# Each participant generate share for other participants and send it.
received_shares = {}
1.upto(max_signer) do |i|
polynomial = secrets[i] # own secret
1.upto(max_signer) do |o|
next if i == o
received_shares[o] ||= []
received_shares[o] << [i, polynomial.gen_share(o)]
end
end

# Each participant verify received shares.
1.upto(max_signer) do |i|
received_shares[i].each do |send_by, share|
target_package = received_package[i].find{ |package| package.identifier == send_by }
expect(target_package.verify_share(share)).to be true
end
end

# Each participant compute signing share.
signing_shares = {}
1.upto(max_signer) do |i|
shares = received_shares[i].map{|_, share| share}
signing_shares[i] = FROST::DKG.compute_signing_share(secrets[i], shares)
end

# Participant 1 compute group public key.
group_pubkey = FROST::DKG.compute_group_pubkey(secrets[1], received_package[1])

# The subsequent signing phase is the same as above with signing_shares as the secret.
```
26 changes: 24 additions & 2 deletions lib/frost/dkg.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ def part1(identifier, min_signers, max_signers, group)
# @param [FROST::Polynomial] polynomial Polynomial containing secret.
# @return [FROST::Signature]
def gen_proof_of_knowledge(identifier, polynomial)
raise ArgumentError, "identifier must be Integer." unless identifier.is_a?(Integer)
raise ArgumentError, "polynomial must be FROST::Polynomial." unless polynomial.is_a?(FROST::Polynomial)

k = SecureRandom.random_number(polynomial.group.order - 1)
r = polynomial.group.generator * k
a0 = polynomial.coefficients.first
Expand All @@ -43,16 +46,35 @@ def gen_proof_of_knowledge(identifier, polynomial)
# @param [FROST::DKG::Package] package Received package.
# @return [Boolean]
def verify_proof_of_knowledge(package)
raise ArgumentError, "package must be FROST::DKG::Package." unless package.is_a?(FROST::DKG::Package)

verification_key = package.verification_key
msg = FROST.encode_identifier(package.identifier, verification_key.group) +
[verification_key.to_hex + package.proof.r.to_hex].pack("H*")
challenge = Hash.hdkg(msg, verification_key.group)
package.proof.r == verification_key.group.generator * package.proof.s + (verification_key * challenge).negate
end

# Performs the second part of DKG.
def part2(packages)
# Compute signing share using received shares from other participants
# @param [FROST::Polynomial] polynomial Own polynomial contains own secret.
# @param [Array] received_shares Array of FROST::SecretShare received by other participants.
# @return [FROST::SecretShare] Signing share.
def compute_signing_share(polynomial, received_shares)
raise ArgumentError, "polynomial must be FROST::Polynomial." unless polynomial.is_a?(FROST::Polynomial)
identifier = received_shares.first.identifier
s_id = received_shares.sum {|share| share.share}
field = ECDSA::PrimeField.new(polynomial.group.order)
FROST::SecretShare.new(
identifier, field.mod(s_id + polynomial.gen_share(identifier).share), polynomial.group)
end

# Compute Group public key.
# @param [FROST::Polynomial] polynomial Own polynomial contains own secret.
# @param [Array] received_packages Array of FROST::DKG::Package received by other participants.
# @return [ECDSA::Point] Group public key.
def compute_group_pubkey(polynomial, received_packages)
raise ArgumentError, "polynomial must be FROST::Polynomial." unless polynomial.is_a?(FROST::Polynomial)
received_packages.inject(polynomial.verification_point) {|sum, package| sum + package.commitments.first }
end
end
end
12 changes: 12 additions & 0 deletions lib/frost/polynomial.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@ def gen_proof_of_knowledge(identifier)
FROST::DKG.gen_proof_of_knowledge(identifier, self)
end

# Get secret value in this polynomial.
# @return [Integer] secret
def secret
coefficients.first
end

# Get point to correspond to secret in this polynomial.
# @return [ECDSA::Point] secret point
def verification_point
group.generator * secret
end

# Generates the lagrange coefficient for the i'th participant.
# @param [Array] x_coordinates The list of x-coordinates.
# @param [Integer] xi an x-coordinate contained in x_coordinates.
Expand Down
51 changes: 51 additions & 0 deletions spec/fixtures/p256/vectors_dkg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"config": {
"MAX_PARTICIPANTS": 3,
"MIN_PARTICIPANTS": 2,
"name": "FROST(P-256, SHA-256)",
"group": "P-256",
"hash": "SHA-256"
},
"inputs": {
"verifying_key": "03639d2ad039e39ae2d7f9a28955a55061d76f0e7b518476c5e5ffa33d1bb9fdb3",
"1": {
"identifier": 1,
"signing_key": "32feae119a184fda4be258289dbce37b1811500600d4e8e9497f0fbd136d052e",
"coefficient": "416eb3b9040da27d2ad3dd812982f9f6da30da9309ae2fcb859fda9f7dcde0e6",
"vss_commitments": ["02a67c8f918d275e9d56108e5eeca8de70b21bdfe4d61d9785b0535d69c52d3f6c", "03e9140b2bcf116755a3397cfc2b3b7bd09a54e3b3544cd81f7e62eb3cc872143a"],
"proof_of_knowledge": "03f77e767e8245f49231442f16b3a7198a1140fac2777d38a6a453a9cc3bca82bb4ef8bc7a32d2d80c275862059fe13a29461c4d2abb3f9c4ae5e718eba907372a",
"signing_shares": {
"2": "a3405e99a61c369a98df1107cd4bd26906e2c55997ad060ca7e7a7744585a03a",
"3": "aea6852c4fe45e87c03a5f2d7b29c7872026cd0e3ca919f324d131564eaf303f"
},
"verifying_share": "036b59b8128e00afa2a334b19d075695a5c79e59d28dfbaa7945b1520f45edfc52",
"signing_share": "c654459194268778cfcfa5df0fb577625c64c25337c19a2fa81df864290c913c"
},
"2": {
"identifier": 2,
"signing_key": "ace068a672458c645a313b57f0eb33b160281a9d458df65f6da9a83c078dfb7b",
"coefficient": "f65ff5f233d6aa373eadd5afdc609eb763a1a569f936ae322df7c9fb3a5aca10",
"vss_commitments": ["037ef641c6fe1f49b9940d06a453bf7b3c230713e5ffe7a2e2a4bb373ddba074ef", "0384662ca5e0da725028206063e9226b28a535645ca4d7024284813b1dc9d91abb"],
"proof_of_knowledge": "02c1b8317d76016aeed7300b39c945fd6130f1cef4a3c72ca1fb93a60f54f683a93f6593b42facb608c001d760e84f3bef7066a082f3482386a7ee66d441723ada",
"signing_shares": {
"1": "b5dc1583a23394d4a18a132af0c2d768cc73052c1431488054bec4fc0f08c6fa",
"3": "7ef45ddf14f100f50e6e198b118743392078ab353cfea5d4698a38ff33d490d8"
},
"verifying_share": "02f928ad1fd3679fd5e73b39e6233068451411dfbb52d4f465c18a176f6be49ce1",
"signing_share": "ce70c7f0911776998785136dabf68bc2dda225c993e46589acb4d9e4c9f7777a"
},
"3": {
"identifier": 3,
"signing_key": "de58ac798ad7bc1a7206a4cfe4cc4bd51fd4eee73c538e11e01829ad6989cfa6",
"coefficient": "d04dd8b1c50ca26e4e33ba5d965d7bb1bd38d8d4a76d2a663872d26be18885ea",
"vss_commitments": ["0363edc1382241228fc6925dc1789737beec5baae430acc6a113581507fac5cf0e", "03156aff5630761ef046d82a52a813b9043653551636774691590bfedab18efef7"],
"proof_of_knowledge": "024c4d52fe40b0b9cea36d842f91fb244a9c09a96954aedb1ffce08a55296d1b4e09225ae0807611f173821e7c15e2ed7c7d0fa26e5fda5d283e2c96f832df906a",
"signing_shares": {
"1": "f74ac93ca6413751cc5df0ac1a45d15fa6a3dfbf1ddf784bda5e9f9b8cd6a7e0",
"2": "90004a800dc98b07163abc67860d0fd854581ad23beb25671c63a5e4c174e9b8"
},
"verifying_share": "028e818f24bcadbb04f60c352a9cbe25568a737279cc6db3a91857ab7c992a1aad",
"signing_share": "d68d4a4f8e0865ba3f3a80fc4837a0235edf893ff00730e3b14bbb656ae25db8"
}
}
}
51 changes: 51 additions & 0 deletions spec/fixtures/secp256k1/vectors_dkg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"config": {
"MAX_PARTICIPANTS": 3,
"MIN_PARTICIPANTS": 2,
"name": "FROST(secp256k1, SHA-256)",
"group": "secp256k1",
"hash": "SHA-256"
},
"inputs": {
"verifying_key": "037b5b0c4b6c91a16fb78499e8a74cc792f9ea79cb94860fcb90f801472930de47",
"1": {
"identifier": 1,
"signing_key": "e7a3cf1fdb1e17d4c3e8a7f663803ef305d03bdfdc930b824b0664c6b853156d",
"coefficient": "819adb51466d687c3944f8dad799a09551af9c083c918a50d9a24a883ae86e2a",
"vss_commitments": ["02dd81b7019efd1d38352b8df26a47d8e6bcb4ce7db71b2f9739b01031105294e2", "03cad1d1bc9d75de15ed0b4cb49dbde670d70988aa96d7982a25ee5484c97d3efc"],
"proof_of_knowledge": "0304df6af7f67b0d5f49ea2116f2d561a0a535c184836779f0f0677ff0838740ce20a0cb076384312f8817e030ca20379bab9247ee56fc3576b0b092f01c005691",
"signing_shares": {
"2": "3c4ae6fe69d55280cb06a0551f8563e526ee6f133a99433addcbb722a4c6f438",
"3": "e2454ec522749fc08388fed9c120b6ada8e1fd1e00026624c95b273f94dbf8a8"
},
"verifying_share": "02b2597e19a037ba2eef224402a50652be93c1ab5bbd6195fc07ae6f6ecfa1304d",
"signing_share": "87cee034add572924bbd40001bbffa1db1f28a4bf52efebb4c2ad0978c71edf5"
},
"2": {
"identifier": 2,
"signing_key": "ea163e297661aadf460b3de39a7550bd9b8fb2d07f1e1db5af098720156591a5",
"coefficient": "5234a8d4f373a7a184fb627185101326460d99296ac3c5c0ee948e8f5f97a3d4",
"vss_commitments": ["0280709e1bc38ca14a42f04dde31b33308d5a7ed7ef79a87c0cc14200783b519ac", "03490b38389a84ea57fde7b369962a92c53b367c221d5cd4728a7c6dfddb337c51"],
"proof_of_knowledge": "02afffa1f80fd46f2bac01bf7967649014a3a5236a62f32f98ce11fec20ee7229072c534d89a6b7b4c16129780404e172c3bdb527a77d40d760b80cc6538bcd4c4",
"signing_shares": {
"1": "ead985c267f8e8cd367299ac12b3801eee809709a66d7fe83e789b4a5dedb080",
"3": "39ee690094ac23a2373b35714ae7d3dc0e07e380bf547bf71758903d291a3e0b"
},
"verifying_share": "03037adc4e0f796b96fc639ac194c1e167ccc5dd57505c813b0533b2bcd6d6ddaa",
"signing_share": "b3477e9659ee0691bdafd1e40230cb07aed5a5e05bd6649f625f12acbb304556"
},
"3": {
"identifier": 3,
"signing_key": "8a9c3489b03d1bdecfd6c84237599980890d39d49167b016bb8b5fb530677204",
"coefficient": "57a91a3b723783e1b3b2369789c71d2d1fd4c3496e9ab60e0dcfc78a647486a4",
"vss_commitments": ["03f26b76678fe0174196430bb94e4e688044ae7bae2ccd7fef21c354429eb8bd61", "020d7a0d25b4ebed5157daf56aba2b89c3e0522f3bc293cc5e138f10e9c5efa465"],
"proof_of_knowledge": "02ad586ef180cda6bae1d2144ee090d277c77b789c8261349a247073626373cd8723b0ea6a62e8bc37372567ab4ef221d5e0a6c46d57d3746f6e5fde863298a542",
"signing_shares": {
"1": "6c746113ae6651496fb79286ea4d20b58581562b33b669fd58488745c89fdd69",
"2": "e0b438a850bca1c3d4fd653829a58a31b309a1661020cebcbaf4d44163f63be0"
},
"verifying_share": "02f2198ff3f1e1de2249cdc59eb4ec926936892fa39fc1582861ad2e84681624b3",
"signing_share": "dec01cf806069a912fa263c7e8a19bf1abb8c174c27dca83789354c1e9ee9cb7"
}
}
}
Loading

0 comments on commit b129f03

Please sign in to comment.