Module: FROST::DKG

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

Overview

Distributed Key Generation feature.

Defined Under Namespace

Classes: Package

Class Method Summary collapse

Class Method Details

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

Compute Group public key.

Parameters:

  • polynomial (FROST::Polynomial)

    Own polynomial contains own secret.

  • received_packages (Array)

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

Returns:

  • (ECDSA::Point)

    Group public key.

Raises:

  • (ArgumentError)


75
76
77
78
# File 'lib/frost/dkg.rb', line 75

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

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

Compute signing share using received shares from other participants

Parameters:

  • polynomial (FROST::Polynomial)

    Own polynomial contains own secret.

  • received_shares (Array)

    Array of FROST::SecretShare received by other participants.

Returns:

Raises:

  • (ArgumentError)


62
63
64
65
66
67
68
69
# File 'lib/frost/dkg.rb', line 62

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

.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)


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

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) ⇒ Array

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:

  • (Array)

    The triple of polynomial and public package(FROST::DKG::Package)

Raises:

  • (ArgumentError)


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

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, "max_signers must be greater than or equal to min_signers." if max_signers < min_signers

  secret = FROST::SigningKey.generate(group)
  # Every participant P_i samples t random values (a_{i0}, ..., a_{i(t−1)}) ← Z_q
  polynomial = secret.gen_poly(min_signers - 1)
  [polynomial, Package.new(identifier, polynomial.gen_commitments, polynomial.gen_proof_of_knowledge(identifier))]
end

.verify_proof_of_knowledge(package) ⇒ Boolean

Verify proof of knowledge for received commitment.

Parameters:

Returns:

  • (Boolean)

Raises:

  • (ArgumentError)


48
49
50
51
52
53
54
55
56
# File 'lib/frost/dkg.rb', line 48

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