github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/astrobwt/astrobwt.go (about)

     1  package astrobwt
     2  
     3  //import "fmt"
     4  import "strings"
     5  import "errors"
     6  import "sort"
     7  import "golang.org/x/crypto/sha3"
     8  import "encoding/binary"
     9  import "golang.org/x/crypto/salsa20/salsa"
    10  
    11  // see here to improve the algorithms more https://github.com/y-256/libdivsufsort/blob/wiki/SACA_Benchmarks.md
    12  
    13  // ErrInvalidSuffixArray means length of sa is not equal to 1+len(s)
    14  var ErrInvalidSuffixArray = errors.New("bwt: invalid suffix array")
    15  
    16  // Transform returns Burrows–Wheeler transform of a byte slice.
    17  // See https://en.wikipedia.org/wiki/Burrows%E2%80%93Wheeler_transform
    18  func Transform(s []byte, es byte) ([]byte, error) {
    19  	sa := SuffixArray(s)
    20  	bwt, err := FromSuffixArray(s, sa, es)
    21  	return bwt, err
    22  }
    23  
    24  // InverseTransform reverses the bwt to original byte slice. Not optimized yet.
    25  func InverseTransform(t []byte, es byte) []byte {
    26  
    27  	le := len(t)
    28  	table := make([]string, le)
    29  	for range table {
    30  		for i := 0; i < le; i++ {
    31  			table[i] = string(t[i:i+1]) + table[i]
    32  		}
    33  		sort.Strings(table)
    34  	}
    35  	for _, row := range table {
    36  		if strings.HasSuffix(row, "$") {
    37  			return []byte(row[:le-1])
    38  		}
    39  	}
    40  	return []byte("")
    41  
    42  	/*
    43  		n := len(t)
    44  		lines := make([][]byte, n)
    45  		for i := 0; i < n; i++ {
    46  			lines[i] = make([]byte, n)
    47  		}
    48  
    49  		for i := 0; i < n; i++ {
    50  			for j := 0; j < n; j++ {
    51  				lines[j][n-1-i] = t[j]
    52  			}
    53  			sort.Sort(byteutil.SliceOfByteSlice(lines))
    54  		}
    55  
    56  		s := make([]byte, n-1)
    57  		for _, line := range lines {
    58  			if line[n-1] == es {
    59  				s = line[0 : n-1]
    60  				break
    61  			}
    62  		}
    63  		return s
    64  	*/
    65  }
    66  
    67  // SuffixArray returns the suffix array of s.
    68  func SuffixArray(s []byte) []int {
    69  	_sa := New(s)
    70  	var sa []int = make([]int, len(s)+1)
    71  	sa[0] = len(s)
    72  	for i := 0; i < len(s); i++ {
    73  		sa[i+1] = int(_sa.sa.int32[i])
    74  	}
    75  	return sa
    76  }
    77  
    78  // FromSuffixArray compute BWT from sa
    79  func FromSuffixArray(s []byte, sa []int, es byte) ([]byte, error) {
    80  	if len(s)+1 != len(sa) || sa[0] != len(s) {
    81  		return nil, ErrInvalidSuffixArray
    82  	}
    83  	bwt := make([]byte, len(sa))
    84  	bwt[0] = s[len(s)-1]
    85  	for i := 1; i < len(sa); i++ {
    86  		if sa[i] == 0 {
    87  			bwt[i] = es
    88  		} else {
    89  			bwt[i] = s[sa[i]-1]
    90  		}
    91  	}
    92  	return bwt, nil
    93  }
    94  
    95  func BWT(input []byte) ([]byte, int) {
    96  	if len(input) >= maxData32 {
    97  		panic("input too big to handle")
    98  	}
    99  	sa := make([]int32, len(input)+1)
   100  	text_32(input, sa[1:])
   101  
   102  	bwt := make([]byte, len(input)+1)
   103  	bwt[0] = input[len(input)-1]
   104  	emarker := 0
   105  	for i := 1; i < len(sa); i++ {
   106  		if sa[i] == 0 {
   107  			//bwt[i] = '$' //es
   108  			emarker = i
   109  		} else {
   110  			bwt[i] = input[sa[i]-1]
   111  		}
   112  
   113  	}
   114  	//bwt[emarker] = '$'
   115  	return bwt, emarker
   116  }
   117  
   118  const stage1_length int = 147253 // it is a prime
   119  const MAX_LENGTH int = 1024*1024 + stage1_length + 1024
   120  
   121  func POW(inputdata []byte) (outputhash [32]byte) {
   122  
   123  	var counter [16]byte
   124  
   125  	key := sha3.Sum256(inputdata)
   126  
   127  	var stage1 [stage1_length]byte                    // stages are taken from it
   128  	var stage2 [1024*1024 + stage1_length + 1024]byte   
   129  
   130  	salsa.XORKeyStream(stage1[:stage1_length], stage1[:stage1_length], &counter, &key)
   131  
   132  	stage1_result, eos := BWT(stage1[:stage1_length])
   133  
   134  	key = sha3.Sum256(stage1_result)
   135  
   136  	stage2_length := stage1_length + int(binary.LittleEndian.Uint32(key[:])&0xfffff)
   137  
   138  	for i := range counter { // will be optimized by compiler
   139  		counter[i] = 0
   140  	}
   141  
   142  	salsa.XORKeyStream(stage2[:stage2_length], stage2[:stage2_length], &counter, &key)
   143  
   144  	stage2_result, eos := BWT(stage2[:stage2_length])
   145  
   146  	//	fmt.Printf("result %x  stage2_length %d \n", key, stage2_length)
   147  	key = sha3.Sum256(stage2_result)
   148  
   149  	//fmt.Printf("result %x\n", key)
   150  
   151  	copy(outputhash[:], key[:])
   152  
   153  	_ = eos
   154  	return
   155  }
   156  
   157  // input byte
   158  // sa should be len(input) + 1
   159  // result len len(input) + 1
   160  func BWT_0alloc(input []byte, sa []int32, bwt []byte) int {
   161  
   162  	//ix := &Index{data: input}
   163  	if len(input) >= maxData32 {
   164  		panic("input too big to handle")
   165  	}
   166  	if len(sa) != len(input)+1 {
   167  		panic("invalid sa array")
   168  	}
   169  	if len(bwt) != len(input)+1 {
   170  		panic("invalid bwt array")
   171  	}
   172  	//sa := make([]int32, len(input)+1)
   173  	text_32(input, sa[1:])
   174  
   175  	//bwt := make([]byte, len(input)+1)
   176  	bwt[0] = input[len(input)-1]
   177  	emarker := 0
   178  	for i := 1; i < len(sa); i++ {
   179  		if sa[i] == 0 {
   180  			//bwt[i] = '$' //es
   181  			emarker = i
   182  		} else {
   183  			bwt[i] = input[sa[i]-1]
   184  		}
   185  
   186  	}
   187  	//bwt[emarker] = '$'
   188  	return emarker
   189  }
   190  func POW_0alloc(inputdata []byte) (outputhash [32]byte) {
   191  
   192  	var counter [16]byte
   193  
   194  	var sa [MAX_LENGTH]int32
   195  	// var bwt [max_length]int32
   196  
   197  	var stage1 [stage1_length]byte // stages are taken from it
   198  	var stage1_result [stage1_length + 1]byte
   199  	var stage2 [1024*1024 + stage1_length + 1]byte 
   200  	var stage2_result [1024*1024 + stage1_length + 1]byte
   201  
   202  	key := sha3.Sum256(inputdata)
   203  
   204  	salsa.XORKeyStream(stage1[:stage1_length], stage1[:stage1_length], &counter, &key)
   205  
   206  	eos := BWT_0alloc(stage1[:stage1_length], sa[:stage1_length+1], stage1_result[:stage1_length+1])
   207  
   208  	key = sha3.Sum256(stage1_result[:])
   209  
   210  	stage2_length := stage1_length + int(binary.LittleEndian.Uint32(key[:])&0xfffff)
   211  
   212  	for i := range counter { // will be optimized by compiler
   213  		counter[i] = 0
   214  	}
   215  
   216  	salsa.XORKeyStream(stage2[:stage2_length], stage2[:stage2_length], &counter, &key)
   217  
   218  	for i := range sa {
   219  		sa[i] = 0
   220  	}
   221  
   222  	eos = BWT_0alloc(stage2[:stage2_length], sa[:stage2_length+1], stage2_result[:stage2_length+1])
   223  	_ = eos
   224  
   225  	key = sha3.Sum256(stage2_result[:stage2_length+1])
   226  
   227  	copy(outputhash[:], key[:])
   228  	return
   229  }