XYOracleNetwork/sdk-core-kotlin

View on GitHub
core-android-library/src/main/kotlin/network/xyo/sdkcorekotlin/boundWitness/XyoBoundWitness.kt

Summary

Maintainability
A
4 hrs
Test Coverage
package network.xyo.sdkcorekotlin.boundWitness

import network.xyo.sdkcorekotlin.schemas.XyoInterpret
import network.xyo.sdkcorekotlin.hashing.XyoHash
import network.xyo.sdkcorekotlin.schemas.XyoSchemas
import network.xyo.sdkcorekotlin.crypto.signing.XyoSigner
import network.xyo.sdkobjectmodelkotlin.structure.XyoObjectStructure
import network.xyo.sdkobjectmodelkotlin.structure.XyoIterableStructure


/**
 * A Bound Witness Object that is independent of origin state. This implements the cryptographic structure discussed
 * in the XYO Network Yellow Paper, and White Paper.
 */
open class XyoBoundWitness(byteArray: ByteArray = startingBytes, offset: Int = 0) : XyoIterableStructure(byteArray, offset) {

    /**
     * If the bound witness is completed or not. This is represented by the number of fetters and the number of
     * witnesses and not 0.
     */
    val completed: Boolean
        get() {
            if ((this[XyoSchemas.FETTER.id].size == this[XyoSchemas.WITNESS.id].size)
                    && this[XyoSchemas.WITNESS.id].isNotEmpty()) {
                return true
            }
            return false
        }

    /**
     * Gets the offset of the boundary to read for signing. This is where the fetters meet the witnesses.
     */
    private val witnessFetterBoundary: Int
        get() {
            val fetters = this[XyoSchemas.FETTER.id]
            var offsetSize = 0

            for (fetter in fetters) {
                offsetSize += fetter.sizeBytes + 2
            }

            return offsetSize
        }

    /**
     * Gets the number of parties in the bound witness
     */
    val numberOfParties : Int?
        get() = getNumberOfParties(this)

    /**
     * Gets the number of fetters in the current bound witness.
     */
    protected val numberOfFetters : Int
        get() {
            return this[XyoSchemas.FETTER.id].size
        }

    /**
     * Gets the number of witnesses in the current bound witness.
     */
    protected val numberOfWitnesses : Int
        get() {
            return this[XyoSchemas.WITNESS.id].size
        }

    /**
     * Gets a fetter from a party in a bound witness.
     *
     * @param partyNum The index of the party in the bound witness.
     * @return The party's fetter. Will return null if out of index.
     */
    fun getFetterOfParty(partyNum : Int) : XyoIterableStructure? {
        val numOfParties = numberOfParties ?: return null

        if (numOfParties <= partyNum) {
            return null
        }

        return getBoundWitnessItemAtIndex(partyNum)
    }

    /**
     * Gets a witness from a party in a bound witness.
     *
     * @param partyNum The index of the party in the bound witness.
     * @return The party's witness. Will return null if out of index.
     */     
    fun getWitnessOfParty(partyNum: Int) : XyoIterableStructure? {
        val numOfParties = numberOfParties ?: return null

        if (numOfParties <= partyNum) {
            return null
        }

        return getBoundWitnessItemAtIndex((numOfParties * 2) - (partyNum + 1))
    }

    /**
     * Gets party information for an index (should only be fetters or witnesses)
     *
     * @param posIndex The index to grab from.
     * @return Will return null if the pos index is out of range or if the bound witness is incomplete.
     */
    fun getBoundWitnessItemAtIndex (posIndex : Int) : XyoIterableStructure? {
        if (completed) {
            return this[posIndex] as? XyoIterableStructure
        }

        return null
    }

    /**
     * Gets the signing data of the bound witness. This is all of the fetters.
     */

    internal val signingData : ByteArray
        get() = valueCopy.copyOfRange(0, witnessFetterBoundary)

    /**
     * Creates a fetter with the given payload and publicKeys.
     *
     * @param payload The payloads to add to the fetter.
     * @param publicKeys The public keys to add to the fetter. This type should be a key set.
     * @return The newly created fetter.
     */
    protected fun createFetter (payload: Array<XyoObjectStructure>, publicKeys : XyoObjectStructure) : XyoObjectStructure {
        val itemsInFetter = ArrayList<XyoObjectStructure>()
        itemsInFetter.add(publicKeys)
        itemsInFetter.addAll(payload)
        return XyoIterableStructure.createUntypedIterableObject(XyoSchemas.FETTER, itemsInFetter.toTypedArray())
    }

    /**
     * Creates a witness with the given payload and signatures.
     *
     * @param payload The payloads to add to the witness.
     * @param signatures The public keys to add to the witness. This type should be a signature set.
     * @return The newly created witness.
     */
    protected fun createWitness (payload: Array<XyoObjectStructure>, signatures : XyoObjectStructure) : XyoIterableStructure {
        val itemsInWitness = ArrayList<XyoObjectStructure>()
        itemsInWitness.add(signatures)
        itemsInWitness.addAll(payload)
        return XyoIterableStructure.createUntypedIterableObject(XyoSchemas.WITNESS, itemsInWitness.toTypedArray())
    }

    /**
     * Gets the hash of the bound witness.
     *
     * @param hashCreator A hash provider to create the hash with.
     * @return A deferred XyoHash
     */
    suspend fun getHash(hashCreator: XyoHash.XyoHashProvider): XyoHash {
        return hashCreator.createHash(signingData)
    }

    /**
     * Creates a signature of the bound witness.
     *
     * @param signer A signer to sign with.
     * @return A deferred XyoObject (signature).
     */
    suspend fun signCurrent(signer: XyoSigner) : XyoObjectStructure {
        return signer.signData(signingData)
    }


    companion object : XyoInterpret {

        /**
        * Gets bytes from an untyped bound witness
        */

        val startingBytes = XyoIterableStructure.createUntypedIterableObject(XyoSchemas.BW, arrayOf()).bytesCopy

        /**
         * Gets a new instance of the bound witness from bytes.
         *
         * @param byteArray The byes of the bound witness to create.
         * @return The XyoBuff bound witness.
         */
        override fun getInstance(byteArray: ByteArray): XyoBoundWitness {
            return XyoBoundWitness(byteArray, 0)
        }

        /**
         * Will get the number of parties in a bound witness.
         *
         * @param boundWitness The boundWitness to check
         * @return The number of parties, if null, there is a inconsistent amount of parties.
         */
        fun getNumberOfParties (boundWitness: XyoBoundWitness) : Int? {
            val numberOfFetters = boundWitness[XyoSchemas.FETTER.id].size
            val numberOfWitnesses= boundWitness[XyoSchemas.WITNESS.id].size

            if (numberOfFetters == numberOfWitnesses) {
                return numberOfFetters
            }

            return null
        }
    }
}