Module: FROST::DKG

Defined in:
lib/frost/dkg.rb,
lib/frost/dkg/package.rb,
lib/frost/dkg/secret_package.rb

Overview

Distributed Key Generation feature.

Defined Under Namespace

Classes: Package, SecretPackage

Class Method Summary collapse

Class Method Details

.compute_group_pubkey(secret_package, received_packages) ⇒ ECDSA::Point

Compute Group public key.

Parameters:

  • secret_package (FROST::DKG::SecretPackage)

    Own secret received_package.

  • received_packages (Array)

    Array of FROST::DKG::Package received by other participants.

Returns:

  • (ECDSA::Point)

    Group public key.

Raises:

  • (ArgumentError)


82
83
84
85
86
87
# File 'lib/frost/dkg.rb', line 82

def compute_group_pubkey(secret_package, received_packages)
  raise ArgumentError, "polynomial must be FROST::DKG::SecretPackage." unless secret_package.is_a?(FROST::DKG::SecretPackage)
  raise FROST::Error, "Invalid number of received_packages." unless secret_package.max_signers - 1 == received_packages.length

  received_packages.inject(secret_package.verification_point) {|sum, package| sum + package.commitments.first }
end

.compute_signing_share(secret_package, received_shares) ⇒ FROST::SecretShare

Compute signing share using received shares from other participants

Parameters:

  • secret_package (FROST::DKG::SecretPackage)

    Own secret received_package.

  • received_shares (Array)

    Array of FROST::SecretShare received by other participants.

Returns:

Raises:

  • (ArgumentError)


67
68
69
70
71
72
73
74
75
76
# File 'lib/frost/dkg.rb', line 67

def compute_signing_share(secret_package, received_shares)
  raise ArgumentError, "polynomial must be FROST::DKG::SecretPackage." unless secret_package.is_a?(FROST::DKG::SecretPackage)
  raise FROST::Error, "Invalid number of received_shares." unless secret_package.max_signers - 1 == received_shares.length

  identifier = received_shares.first.identifier
  s_id = received_shares.sum {|share| share.share}
  field = ECDSA::PrimeField.new(secret_package.group.order)
  FROST::SecretShare.new(
    identifier, field.mod(s_id + secret_package.gen_share(identifier).share), secret_package.group)
end

.gen_proof_of_knowledge(identifier, polynomial) ⇒ FROST::Signature

Generate proof of knowledge for secret.

Parameters:

  • identifier (Integer)

    Identifier of the owner of polynomial.

  • polynomial (FROST::Polynomial)

    Polynomial containing secret.

Returns:

Raises:

  • (ArgumentError)


32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/frost/dkg.rb', line 32

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
  a0_g = polynomial.group.generator * a0
  msg = FROST.encode_identifier(identifier, polynomial.group) + [a0_g.to_hex + r.to_hex].pack("H*")
  challenge = Hash.hdkg(msg, polynomial.group)
  field = ECDSA::PrimeField.new(polynomial.group.order)
  s = field.mod(k + a0 * challenge)
  FROST::Signature.new(r, s)
end

.generate_secret(identifier, min_signers, max_signers, group) ⇒ FROST::DKG::SecretPackage

Performs the first part of the DKG. Participant generate key and commitments, proof of knowledge for secret.

Parameters:

  • identifier (Integer)
  • group (ECDSA::Group)

    Group of elliptic curve.

Returns:

Raises:

  • (ArgumentError)


15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/frost/dkg.rb', line 15

def generate_secret(identifier, min_signers, max_signers, group)
  raise ArgumentError, "identifier must be Integer" unless identifier.is_a?(Integer)
  raise ArgumentError, "identifier must be greater than 0." if identifier < 1
  raise ArgumentError, "group must be ECDSA::Group." unless group.is_a?(ECDSA::Group)
  raise ArgumentError, "min_signers must be Integer." unless min_signers.is_a?(Integer)
  raise ArgumentError, "max_singers must be Integer." unless max_signers.is_a?(Integer)
  raise ArgumentError, "max_signers must be greater than or equal to min_signers." if max_signers < min_signers

  secret = FROST::SigningKey.generate(group)
  polynomial = secret.gen_poly(min_signers - 1)
  SecretPackage.new(identifier, min_signers, max_signers, polynomial)
end

.verify_proof_of_knowledge(secret_package, received_package) ⇒ Boolean

Verify proof of knowledge for received commitment.

Parameters:

Returns:

  • (Boolean)

Raises:

  • (ArgumentError)


51
52
53
54
55
56
57
58
59
60
61
# File 'lib/frost/dkg.rb', line 51

def verify_proof_of_knowledge(secret_package, received_package)
  raise ArgumentError, "secret_package must be FROST::DKG::SecretPackage." unless secret_package.is_a?(FROST::DKG::SecretPackage)
  raise ArgumentError, "received_package must be FROST::DKG::Package." unless received_package.is_a?(FROST::DKG::Package)
  raise FROST::Error, "Invalid number of commitments in package." unless secret_package.min_signers == received_package.commitments.length

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