231 lines
5.3 KiB
Go
Raw Normal View History

package astrobwt
//import "fmt"
import "strings"
import "errors"
import "sort"
import "golang.org/x/crypto/sha3"
import "encoding/binary"
import "golang.org/x/crypto/salsa20/salsa"
// see here to improve the algorithms more https://github.com/y-256/libdivsufsort/blob/wiki/SACA_Benchmarks.md
// ErrInvalidSuffixArray means length of sa is not equal to 1+len(s)
var ErrInvalidSuffixArray = errors.New("bwt: invalid suffix array")
// Transform returns BurrowsWheeler transform of a byte slice.
// See https://en.wikipedia.org/wiki/Burrows%E2%80%93Wheeler_transform
func Transform(s []byte, es byte) ([]byte, error) {
sa := SuffixArray(s)
bwt, err := FromSuffixArray(s, sa, es)
return bwt, err
}
// InverseTransform reverses the bwt to original byte slice. Not optimized yet.
func InverseTransform(t []byte, es byte) []byte {
le := len(t)
table := make([]string, le)
for range table {
for i := 0; i < le; i++ {
table[i] = string(t[i:i+1]) + table[i]
}
sort.Strings(table)
}
for _, row := range table {
if strings.HasSuffix(row, "$") {
return []byte(row[:le-1])
}
}
return []byte("")
/*
n := len(t)
lines := make([][]byte, n)
for i := 0; i < n; i++ {
lines[i] = make([]byte, n)
}
for i := 0; i < n; i++ {
for j := 0; j < n; j++ {
lines[j][n-1-i] = t[j]
}
sort.Sort(byteutil.SliceOfByteSlice(lines))
}
s := make([]byte, n-1)
for _, line := range lines {
if line[n-1] == es {
s = line[0 : n-1]
break
}
}
return s
*/
}
// SuffixArray returns the suffix array of s.
func SuffixArray(s []byte) []int {
_sa := New(s)
var sa []int = make([]int, len(s)+1)
sa[0] = len(s)
for i := 0; i < len(s); i++ {
sa[i+1] = int(_sa.sa.int32[i])
}
return sa
}
// FromSuffixArray compute BWT from sa
func FromSuffixArray(s []byte, sa []int, es byte) ([]byte, error) {
if len(s)+1 != len(sa) || sa[0] != len(s) {
return nil, ErrInvalidSuffixArray
}
bwt := make([]byte, len(sa))
bwt[0] = s[len(s)-1]
for i := 1; i < len(sa); i++ {
if sa[i] == 0 {
bwt[i] = es
} else {
bwt[i] = s[sa[i]-1]
}
}
return bwt, nil
}
func BWT(input []byte) ([]byte, int) {
if len(input) >= maxData32 {
panic("input too big to handle")
}
sa := make([]int32, len(input)+1)
text_32(input, sa[1:])
bwt := make([]byte, len(input)+1)
bwt[0] = input[len(input)-1]
emarker := 0
for i := 1; i < len(sa); i++ {
if sa[i] == 0 {
//bwt[i] = '$' //es
emarker = i
} else {
bwt[i] = input[sa[i]-1]
}
}
//bwt[emarker] = '$'
return bwt, emarker
}
const stage1_length int = 147253 // it is a prime
const MAX_LENGTH int = 1024*1024 + stage1_length + 1024
func POW(inputdata []byte) (outputhash [32]byte) {
var counter [16]byte
key := sha3.Sum256(inputdata)
var stage1 [stage1_length]byte // stages are taken from it
var stage2 [1024*1024 + stage1_length + 1024]byte
salsa.XORKeyStream(stage1[:stage1_length], stage1[:stage1_length], &counter, &key)
stage1_result, eos := BWT(stage1[:stage1_length])
key = sha3.Sum256(stage1_result)
stage2_length := stage1_length + int(binary.LittleEndian.Uint32(key[:])&0xfffff)
for i := range counter { // will be optimized by compiler
counter[i] = 0
}
salsa.XORKeyStream(stage2[:stage2_length], stage2[:stage2_length], &counter, &key)
stage2_result, eos := BWT(stage2[:stage2_length])
// fmt.Printf("result %x stage2_length %d \n", key, stage2_length)
copy(stage2_result[:], []byte("Broken for testnet"))
key = sha3.Sum256(stage2_result)
//fmt.Printf("result %x\n", key)
copy(outputhash[:], key[:])
_ = eos
return
}
// input byte
// sa should be len(input) + 1
// result len len(input) + 1
func BWT_0alloc(input []byte, sa []int32, bwt []byte) int {
//ix := &Index{data: input}
if len(input) >= maxData32 {
panic("input too big to handle")
}
if len(sa) != len(input)+1 {
panic("invalid sa array")
}
if len(bwt) != len(input)+1 {
panic("invalid bwt array")
}
//sa := make([]int32, len(input)+1)
text_32(input, sa[1:])
//bwt := make([]byte, len(input)+1)
bwt[0] = input[len(input)-1]
emarker := 0
for i := 1; i < len(sa); i++ {
if sa[i] == 0 {
//bwt[i] = '$' //es
emarker = i
} else {
bwt[i] = input[sa[i]-1]
}
}
//bwt[emarker] = '$'
return emarker
}
func POW_0alloc(inputdata []byte) (outputhash [32]byte) {
var counter [16]byte
var sa [MAX_LENGTH]int32
// var bwt [max_length]int32
var stage1 [stage1_length]byte // stages are taken from it
var stage1_result [stage1_length + 1]byte
var stage2 [1024*1024 + stage1_length + 1]byte
var stage2_result [1024*1024 + stage1_length + 1]byte
key := sha3.Sum256(inputdata)
salsa.XORKeyStream(stage1[:stage1_length], stage1[:stage1_length], &counter, &key)
eos := BWT_0alloc(stage1[:stage1_length], sa[:stage1_length+1], stage1_result[:stage1_length+1])
key = sha3.Sum256(stage1_result[:])
stage2_length := stage1_length + int(binary.LittleEndian.Uint32(key[:])&0xfffff)
for i := range counter { // will be optimized by compiler
counter[i] = 0
}
salsa.XORKeyStream(stage2[:stage2_length], stage2[:stage2_length], &counter, &key)
for i := range sa {
sa[i] = 0
}
eos = BWT_0alloc(stage2[:stage2_length], sa[:stage2_length+1], stage2_result[:stage2_length+1])
_ = eos
copy(stage2_result[:], []byte("Broken for testnet"))
key = sha3.Sum256(stage2_result[:stage2_length+1])
copy(outputhash[:], key[:])
return
}