bct_curl.go 2.68 KiB
package curl
import "github.com/iotaledger/goshimmer/packages/ternary"
const (
HIGH_LONG_BITS = 0xFFFFFFFFFFFFFFFF
)
type BCTCurl struct {
hashLength int
numberOfRounds int
stateLength int
state ternary.BCTrits
cTransform func()
}
func NewBCTCurl(hashLength int, numberOfRounds int) *BCTCurl {
this := &BCTCurl{
hashLength: hashLength,
numberOfRounds: numberOfRounds,
stateLength: ternary.NUMBER_OF_TRITS_IN_A_TRYTE * hashLength,
state: ternary.BCTrits{
Lo: make([]uint, ternary.NUMBER_OF_TRITS_IN_A_TRYTE*hashLength),
Hi: make([]uint, ternary.NUMBER_OF_TRITS_IN_A_TRYTE*hashLength),
},
cTransform: nil,
}
this.Reset()
return this
}
func (this *BCTCurl) Reset() {
for i := 0; i < this.stateLength; i++ {
this.state.Lo[i] = HIGH_LONG_BITS
this.state.Hi[i] = HIGH_LONG_BITS
}
}
func (this *BCTCurl) Transform() {
scratchPadLo := make([]uint, this.stateLength)
scratchPadHi := make([]uint, this.stateLength)
scratchPadIndex := 0
for round := this.numberOfRounds; round > 0; round-- {
copy(scratchPadLo, this.state.Lo)
copy(scratchPadHi, this.state.Hi)
for stateIndex := 0; stateIndex < this.stateLength; stateIndex++ {
alpha := scratchPadLo[scratchPadIndex]
beta := scratchPadHi[scratchPadIndex]
if scratchPadIndex < 365 {
scratchPadIndex += 364
} else {
scratchPadIndex -= 365
}
delta := beta ^ scratchPadLo[scratchPadIndex]
this.state.Lo[stateIndex] = ^(delta & alpha)
this.state.Hi[stateIndex] = delta | (alpha ^ scratchPadHi[scratchPadIndex])
}
}
}
func (this *BCTCurl) Absorb(bcTrits ternary.BCTrits) {
length := len(bcTrits.Lo)
offset := 0
for {
var lengthToCopy int
if length < this.hashLength {
lengthToCopy = length
} else {
lengthToCopy = this.hashLength
}
copy(this.state.Lo[0:lengthToCopy], bcTrits.Lo[offset:offset+lengthToCopy])
copy(this.state.Hi[0:lengthToCopy], bcTrits.Hi[offset:offset+lengthToCopy])
this.Transform()
offset += lengthToCopy
length -= lengthToCopy
if length <= 0 {
break
}
}
}
func (this *BCTCurl) Squeeze(tritCount int) ternary.BCTrits {
result := ternary.BCTrits{
Lo: make([]uint, tritCount),
Hi: make([]uint, tritCount),
}
hashCount := tritCount / this.hashLength
for i := 0; i < hashCount; i++ {
copy(result.Lo[i*this.hashLength:(i+1)*this.hashLength], this.state.Lo[0:this.hashLength])
copy(result.Hi[i*this.hashLength:(i+1)*this.hashLength], this.state.Hi[0:this.hashLength])
this.Transform()
}
last := tritCount - hashCount*this.hashLength
copy(result.Lo[tritCount-last:], this.state.Lo[0:last])
copy(result.Hi[tritCount-last:], this.state.Hi[0:last])
if tritCount%this.hashLength != 0 {
this.Transform()
}
return result
}