0

)

I know this might not be the perfect place to ask, but as ETH is also a Blockchain Tech and also uses Go within their stack, I couldn't find a forum that seems more appropriate.

My Problem: I'm currently having a hard time trying to implement Hash Proofing for Nexus for a NXS mining backend I'm currently working at.

For reference, those are the libs I used:

Nexus Legacy - https://github.com/Nexusoft/Legacy

Golang SHA3 - https://github.com/golang/crypto/tree/master/sha3

Golang Skein1024 - https://github.com/enceve/crypto/tree/master/skein/skein1024

Some code first

The Nexus Skein-Keccak Function is being called with these params (https://github.com/Nexusoft/Legacy/blob/master/src/hash/templates.h):

inline uint1024 SK1024(const T1 pbegin, const T1 pend)
{
    static unsigned char pblank[1];

    uint1024 skein;
    Skein1024_Ctxt_t ctx;
    Skein1024_Init(&ctx, 1024);
    Skein1024_Update(&ctx, (pbegin == pend ? pblank : (unsigned char*)&pbegin[0]), (pend - pbegin) * sizeof(pbegin[0]));
    Skein1024_Final(&ctx, (unsigned char *)&skein);

    uint1024 keccak;
    Keccak_HashInstance ctx_keccak;
    Keccak_HashInitialize(&ctx_keccak, 576, 1024, 1024, 0x05);
    Keccak_HashUpdate(&ctx_keccak, (unsigned char *)&skein, 1024);
    Keccak_HashFinal(&ctx_keccak, (unsigned char *)&keccak);

    return keccak;
}

For My implementation, I implemented a custom BigInt type and also copied over the code from golangs sha3 standard keccak lib, because the typing is mostly private and doesen't allow Simple extension with a Keccak 1024.

Custom BigInt Type:

package nxscore

import (
    "encoding/hex"
    "errors"
)

var (
    ErrInvalidFraming = errors.New("invalid framing")
)

type BigUint struct {
    bytes []uint8
    limit int
}

func Uint1024() *BigUint {
    return &BigUint{
        bytes: make([]uint8, 128),
        limit: 128,
    }
}

func Uint512() *BigUint {
    return &BigUint{
        bytes: make([]uint8, 64),
        limit: 64,
    }
}

func Uint256() *BigUint {
    return &BigUint{
        bytes: make([]uint8, 32),
        limit: 32,
    }
}

func (u *BigUint) GetBytes() []uint8 {
    return u.bytes
}

func (u *BigUint) SetBytes(bytes []uint8) error {
    if len(bytes) > u.limit {
        return ErrInvalidFraming
    }
    u.bytes = bytes
    return nil
}

func (u *BigUint) SetCompact(bits uint32) error {
    size := bits >> 24
    bytes := make([]uint8, 4+size)
    bytes[3] = uint8(size)

    if size >= 1 {
        bytes[4] = uint8(bits>>16) & 0xff
    }
    if size >= 2 {
        bytes[5] = uint8(bits>>8) & 0xff
    }
    if size >= 3 {
        bytes[6] = uint8(bits>>0) & 0xff
    }

    return u.SetBytes(bytes)
}

func (u *BigUint) GetCompact() uint32 {
    bytes := u.GetBytes()
    size := len(bytes)
    size -= 4

    compact := uint32(size) << 24

    if size >= 1 {
        compact |= uint32(bytes[4]) << 16
    }
    if size >= 2 {
        compact |= uint32(bytes[5]) << 8
    }
    if size >= 3 {
        compact |= uint32(bytes[6]) << 0
    }

    return compact
}

func (u *BigUint) String() string {
    return hex.EncodeToString(u.bytes)
}

// Cmp Compares 2 BigUints on byte level
// -1 if c > u
//  0 if c == u
//  1 if c > u
func (u *BigUint) Cmp(c *BigUint) int {
    lu := len(u.bytes)
    lc := len(c.bytes)

    compBytesU := make([]uint8, lu)
    compBytesC := make([]uint8, lu)
    copy(compBytesU, u.bytes)
    copy(compBytesC, c.bytes)

    // Make sure both Ints use the same range
    maxIndex := lu
    if lu < lc {
        maxIndex = lc
        compBytesU = append(make([]uint8, lc-lu), compBytesU...)
    }
    if lu > lc {
        maxIndex = lu
        compBytesC = append(make([]uint8, lu-lc), compBytesC...)
    }

    compResult := 0
    for i := 0; i < maxIndex; i++ {
        if compBytesC[i] > compBytesU[i] {
            compResult = -1
            break
        } else if compBytesC[i] < compBytesU[i] {
            compResult = 1
            break
        }
    }

    return compResult
}

Custom SK1024 Wrapper:

func SK1024(data []uint8) (result *BigUint, err error) {

    // First Round: Skein 1024
    //skBytes := skein1024.Sum(data, 128, nil)
    skBytes := make([]uint8, 0)
    sk := skein1024.New(128, nil)
    sk.Write(data)
    skBytes = sk.Sum(skBytes)

    // Second Round: Keccak 1024
    kcBytes := make([]uint8, 0)
    keccak := New1024()
    keccak.Write(skBytes)
    kcBytes = keccak.Sum(kcBytes)

    // Return as Uint1024
    result = Uint1024()
    err = result.SetBytes(kcBytes)
    return
}

Custom Nexus Block implementation

type Block struct {
    Version        uint32
    PrevBlockHash  *BigUint
    HashMerkleRoot *BigUint
    Channel        uint32
    Height         uint32
    Bits           uint32
    Nonce          uint64
}

func DeserializeBlock(data []uint8) (block Block, err error) {
    length := len(data)

    block = Block{}
    block.Version = util.Bytes2Uint(data[0:4], 0)

    block.PrevBlockHash = Uint1024()
    err = block.PrevBlockHash.SetBytes(data[4:132])
    if err != nil {
        return block, err
    }

    block.HashMerkleRoot = Uint512()
    err = block.HashMerkleRoot.SetBytes(data[132:(length - 20)])
    if err != nil {
        return block, err
    }

    block.Channel = util.Bytes2Uint(data[(length-20):(length-16)], 0)
    block.Height = util.Bytes2Uint(data[(length-16):(length-12)], 0)
    block.Bits = util.Bytes2Uint(data[(length-12):(length-8)], 0)
    block.Nonce = util.Bytes2Uint64(data[(length - 8):length])

    return block, nil
}

func SerializeBlock(b *Block, shareDiffBits []uint8) (data []uint8, err error) {
    data = make([]uint8, 0)

    // Expected by Miners. Really dirty...
    if shareDiffBits != nil {
        data = append(data, shareDiffBits...)
    }

    data = append(data, util.Uint2Bytes(b.Version)...)
    data = append(data, b.PrevBlockHash.GetBytes()...)
    data = append(data, b.HashMerkleRoot.GetBytes()...)
    data = append(data, util.Uint2Bytes(b.Channel)...)
    data = append(data, util.Uint2Bytes(b.Height)...)
    data = append(data, util.Uint2Bytes(b.Bits)...)
    data = append(data, util.Uint2Bytes64(b.Nonce)...)

    return
}

Now what am I trying to do?

For testing my implementation, I took this Block here as example: https://nxsorbitalscan.com/block/2712110

And built a struct instance with it:

prevHashStr := "f49a35e859011c32171daa1e18248d5a30655a8fbaf9b465e9010f40fa1742c907764155d331ce8b773d7fea2f031a6da2c7e2e1f92b03ce93c0fcd9bd5595576a2e0c993e15b79a15c399b71455aa12f523a70b3188b1006e51b4d5cbc61932b1d2525518ff447a2da082459a1abdb610d096ff7055e11d6052e0e17fb3a2f6"
prevHashBytes, _ := hex.DecodeString(prevHashStr)
prevHash := nxscore.Uint1024()
_ = prevHash.SetBytes(prevHashBytes)

merkleRootStr := "163e0e84a9b1d899e1298daafba9814b64ac96cbc0b336892038ead19633a460cc7bda5d21e005818daa3f73056813cd4efe4bf7467e93962d250ce2bfe7909d"
merkleRootBytes, _ := hex.DecodeString(merkleRootStr)
merkleRoot := nxscore.Uint512()
_ = merkleRoot.SetBytes(merkleRootBytes)

testBlock := &nxscore.Block{
    Version:        6,
    PrevBlockHash:  prevHash,
    HashMerkleRoot: merkleRoot,
    Channel:        2,
    Height:         2712110,
    Bits:           2063883824,
    Nonce:          220128845226,
}

Serialized, I get this 216 Byte slice:

[0 0 0 6 244 154 53 232 89 1 28 50 23 29 170 30 24 36 141 90 48 101 90 143 186 249 180 101 233 1 15 64 250 23 66 201 7 118 65 85 211 49 206 139 119 61 127 234 47 3 26 109 162 199 226 225 249 43 3 206 147 192 252 217 189 85 149 87 106 46 12 153 62 21 183 154 21 195 153 183 20 85 170 18 245 35 167 11 49 136 177 0 110 81 180 213 203 198 25 50 177 210 82 85 24 255 68 122 45 160 130 69 154 26 189 182 16 208 150 255 112 85 225 29 96 82 224 225 127 179 162 246 22 62 14 132 169 177 216 153 225 41 141 170 251 169 129 75 100 172 150 203 192 179 54 137 32 56 234 209 150 51 164 96 204 123 218 93 33 224 5 129 141 170 63 115 5 104 19 205 78 254 75 247 70 126 147 150 45 37 12 226 191 231 144 157 0 0 0 2 0 41 98 46 123 4 94 48 0 0 0 51 64 179 157 170]

But when I hash it, I don't receive the expected proof hash as of here:

0000000000042fdd67c7caf76a556eb185ecc60effb41291622ee0f12c44b1f75d93ece14744868e7e4578dd81d7f827e4f9c35958fc81782dc83405a824eda6c0027b75665f5785542da01ebfa9fb998041c7d4842d187c321ed1fa009778a15c2a84706389c524fda41b24d1e4e5cc029acaad9924d0481a29d48ec708242b

So well, I think that's a lot at once. But I hope that maybe still someone can tell me where my mistake is.

BR

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.