Skip to content
Snippets Groups Projects
curl.go 2.01 KiB
Newer Older
package curl

import (
capossele's avatar
capossele committed
	"math"

	"github.com/iotaledger/goshimmer/packages/ternary"
capossele's avatar
capossele committed
	HASH_LENGTH  = 243
	STATE_LENGTH = ternary.NUMBER_OF_TRITS_IN_A_TRYTE * HASH_LENGTH
capossele's avatar
capossele committed
	TRUTH_TABLE = ternary.Trits{1, 0, -1, 2, 1, -1, 0, 2, -1, 1, 0}
)

type Hash interface {
capossele's avatar
capossele committed
	Initialize()
	InitializeCurl(trits *[]int8, length int, rounds int)
	Reset()
	Absorb(trits *[]int8, offset int, length int)
	Squeeze(resp []int8, offset int, length int) []int
capossele's avatar
capossele committed
	Hash
	state      ternary.Trits
	hashLength int
	rounds     int
}

func NewCurl(hashLength int, rounds int) *Curl {
capossele's avatar
capossele committed
	this := &Curl{
		hashLength: hashLength,
		rounds:     rounds,
	}
capossele's avatar
capossele committed
	this.Reset()
capossele's avatar
capossele committed
	return this
}

func (curl *Curl) Initialize() {
capossele's avatar
capossele committed
	curl.InitializeCurl(nil, 0, curl.rounds)
}

func (curl *Curl) InitializeCurl(trinary ternary.Trits, length int, rounds int) {
capossele's avatar
capossele committed
	curl.rounds = rounds
	if trinary != nil {
		curl.state = trinary
	} else {
		curl.state = make(ternary.Trits, STATE_LENGTH)
	}
}

func (curl *Curl) Reset() {
capossele's avatar
capossele committed
	curl.InitializeCurl(nil, 0, curl.rounds)
}

func (curl *Curl) Absorb(trinary ternary.Trits, offset int, length int) {
capossele's avatar
capossele committed
	for {
		limit := int(math.Min(HASH_LENGTH, float64(length)))
		copy(curl.state, trinary[offset:offset+limit])
		curl.Transform()
		offset += HASH_LENGTH
		length -= HASH_LENGTH
		if length <= 0 {
			break
		}
	}
}

func (curl *Curl) Squeeze(resp ternary.Trits, offset int, length int) ternary.Trits {
capossele's avatar
capossele committed
	for {
		limit := int(math.Min(HASH_LENGTH, float64(length)))
		copy(resp[offset:offset+limit], curl.state)
		curl.Transform()
		offset += HASH_LENGTH
		length -= HASH_LENGTH
		if length <= 0 {
			break
		}
	}
	return resp
}

func (curl *Curl) Transform() {
capossele's avatar
capossele committed
	var index = 0
	for round := 0; round < curl.rounds; round++ {
		stateCopy := make(ternary.Trits, STATE_LENGTH)
		copy(stateCopy, curl.state)
		for i := 0; i < STATE_LENGTH; i++ {
			incr := 364
			if index >= 365 {
				incr = -365
			}
			index2 := index + incr
			curl.state[i] = TRUTH_TABLE[stateCopy[index]+(stateCopy[index2]<<2)+5]
			index = index2
		}
	}
}