232 lines
5.3 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}