Multi Signature - zoobc/zoobc-core GitHub Wiki

Multisignature transaction is a transaction that require more than 1 signature to be completed.

  • Multisig Address

    No Name Length Type
    0 participants n []string
    1 minimum_signatures 4 uint32
    2 nonce 8 int64

    Multisig address is a special kind of account address generated to execute multisignature transaction from multiple participants. To generate multisig address we do the following steps:

    • collect and sort the participant address alphabetically ascending.
    • set the number of minimum signatures for the transaction to be valid.
    • set the nounce, a random number that can be set differently if want to get different multisig address from the same participants.

    example:

    multisig_address: {
      participants: [
        participant_1,
        participant_2,
        participant_3,
      ],
      minimum_signatures: 2,
      nonce: 212,
    }
    

    To get the final multisig address, we hash the bytes sequence with sha3_256, then tranlate to zoobc account address encoding

    • Bytes Sequence

      result = BytesArray
      
      result.Write(min_sigs) // 4 bytes
      result.Write(nonce) // 4 bytes
      sortStringAscending(participants)
      result.Write(len(participants)) // 4 bytes
      
      for address := in participants {
        result.Write(address)
      }
      hashed := sha3.Sum256(result) // 32 bytes
      
  • Multisignature Transaction

    Multisignature transaction is separated to two parts:

    • Inner transaction

      Normal transaction that we want to execute setting the multisignature address as the sender, we'll set the signature empty since we don't have private key for this account.

    • Actual transaction (multisignature transaction)

      Wrapper transaction represented by the Multisignature Transaction Type.

    This transaction has three main fields that can be provided in the following combination:

    • Multisignature Info

      The information of the multisig address including the nonce, minimum signatures, and the participants details. This piece of information is required before submitting any other information in on chain way.

    • Transaction Bytes

      The unsigned transaction bytes of inner transaction.

    • Signature Info

      Collective signatures on the transaction bytes sha3_256 hash.

    Multisignature transaction can be executed in two ways:

    • Off Chain

      Submit every information of multisignature transaction on one go, collecting the signatures of individual participants outside of the zoobc core node.

    • On Chain

      Submit the information of multisignature transaction partially, and collecting the (whole / partial) signatures on core node.

    Sender of multisig transaction Actual Transaction can be any account, even outside of the participants, except when submitting the transaction bytes.

    result = BytesArray
    
    if MultisignatureInfo != null {
      result.Write(1) // 4 bytes - indicating multisigInfo Exist
      result.Write(min_sigs) // 4 bytes
      result.Write(nonce) // 4 bytes
      result.Write(len(participants)) // 4 bytes
      for address in participants { // participants have to be sorted
          result.Write(address)
      }
    } else {
      result.Write(0) // 4 bytes - indicating multisigInfo missing
    }
    result.Write(len(UnsignedTransactionBytes)) // zero if missing
    result.Write(UnsignedTransactionBytes) // empty bytes if missing
    
    if SignatureInfo != null {
      result.Write(1) // 4 bytes - indicating signature info present
      result.Write(transactionHash) // 32 bytes
      result.Write(len(signatures))
      for address, signature in signatures {
        result.Write(address)
        result.Write(len(signature)) // 4 bytes
        result.Write(signature)
      }
    }
    

Hierarchical MultiSignature

In multisig transaction type we can submit hierarchical multi-signature transaction, meaning we can add multisig_address as one of the participant in multisig-transaction.

multisig_transaction {
  Sender: participant_a,
  Body: {
    MultisigInfo: {
      MultisigAddress: multisig_address_a,
      Addresses: [
        participant_a,
        participant_b,
        participant_c_multisig_address,
      ],
      Nonce: 1010,
      MinimumSignatures: 2,
    }
  }
}

where participant_c_multisig_address can be detailed as:

MultisigInfo: {
  MultisigAddress: participant_c_multisig_address,
  Addresses: [
    participant_d,
    participant_e,
    participant_f,
  ],
  Nonce: 1,
  MinimumSignatures: 2,
}

To submit a hierarchical multisig transaction we'll need to do in following step:

  • Generate transaction A, in this example let's say we want to send money from multisig_address_a to address_x. Where multisig_address_a will have multisig_address_b as one of its participants.

  • Generate transaction B that wrap transaction A in multisig_transaction with multisig_address_a in MultisigInfo portion of the body.

  • Generate transaction C that will submit participant_c_multisig_address:signature to the transaction B. The signature associated with participant_c_multisig_address will be the value of {2, 0, 0, 0} or model.SignatureType_MultisigSignature, that way the node will recognize this as a valid signature.

  • Generate the transaction that provide signatures, unsigned_transactionBytes, transaction_hash, and multisig_info for transaction C

  • After every information required by transaction C is complete, the body of transaction C which is transaction B will be executed, and add a pending_signature record for transaction A

  • Generate the rest of information to provide transaction A to be valid.

  • With transaction A information complete, its pending_transaction will be executed and that finalized the hierarchical