177 lines
3.3 KiB
Go
177 lines
3.3 KiB
Go
package fr32
|
|
|
|
import (
|
|
"math/bits"
|
|
"runtime"
|
|
"sync"
|
|
|
|
"github.com/filecoin-project/go-state-types/abi"
|
|
)
|
|
|
|
// UnpaddedFr32Chunk is the minimum amount of data which can be fr32-padded
|
|
// Fr32 padding inserts two zero bits every 254 bits, so the minimum amount of
|
|
// data which can be padded is 254 bits. 127 bytes is the smallest multiple of
|
|
// 254 bits which has a whole number of bytes.
|
|
const UnpaddedFr32Chunk abi.UnpaddedPieceSize = 127
|
|
|
|
// PaddedFr32Chunk is the size of a UnpaddedFr32Chunk chunk after fr32 padding
|
|
const PaddedFr32Chunk abi.PaddedPieceSize = 128
|
|
|
|
func init() {
|
|
if PaddedFr32Chunk != UnpaddedFr32Chunk.Padded() {
|
|
panic("bad math")
|
|
}
|
|
}
|
|
|
|
var MTTresh = uint64(512 << 10)
|
|
|
|
func mtChunkCount(usz abi.PaddedPieceSize) uint64 {
|
|
threads := (uint64(usz)) / MTTresh
|
|
if threads > uint64(runtime.NumCPU()) {
|
|
threads = 1 << (bits.Len32(uint32(runtime.NumCPU())))
|
|
}
|
|
if threads == 0 {
|
|
return 1
|
|
}
|
|
if threads > 32 {
|
|
return 32 // avoid too large buffers
|
|
}
|
|
return threads
|
|
}
|
|
|
|
func mt(in, out []byte, padLen int, op func(unpadded, padded []byte)) {
|
|
threads := mtChunkCount(abi.PaddedPieceSize(padLen))
|
|
threadBytes := abi.PaddedPieceSize(padLen / int(threads))
|
|
|
|
var wg sync.WaitGroup
|
|
wg.Add(int(threads))
|
|
|
|
for i := 0; i < int(threads); i++ {
|
|
go func(thread int) {
|
|
defer wg.Done()
|
|
|
|
start := threadBytes * abi.PaddedPieceSize(thread)
|
|
end := start + threadBytes
|
|
|
|
op(in[start.Unpadded():end.Unpadded()], out[start:end])
|
|
}(i)
|
|
}
|
|
wg.Wait()
|
|
}
|
|
|
|
func Pad(in, out []byte) {
|
|
// Assumes len(in)%127==0 and len(out)%128==0
|
|
if len(out) > int(MTTresh) {
|
|
mt(in, out, len(out), pad)
|
|
return
|
|
}
|
|
|
|
pad(in, out)
|
|
}
|
|
|
|
func PadSingle(in, out []byte) {
|
|
pad(in, out)
|
|
}
|
|
|
|
func pad(in, out []byte) {
|
|
chunks := len(out) / 128
|
|
for chunk := 0; chunk < chunks; chunk++ {
|
|
inOff := chunk * 127
|
|
outOff := chunk * 128
|
|
|
|
copy(out[outOff:outOff+31], in[inOff:inOff+31])
|
|
|
|
t := in[inOff+31] >> 6
|
|
out[outOff+31] = in[inOff+31] & 0x3f
|
|
var v byte
|
|
|
|
for i := 32; i < 64; i++ {
|
|
v = in[inOff+i]
|
|
out[outOff+i] = (v << 2) | t
|
|
t = v >> 6
|
|
}
|
|
|
|
t = v >> 4
|
|
out[outOff+63] &= 0x3f
|
|
|
|
for i := 64; i < 96; i++ {
|
|
v = in[inOff+i]
|
|
out[outOff+i] = (v << 4) | t
|
|
t = v >> 4
|
|
}
|
|
|
|
t = v >> 2
|
|
out[outOff+95] &= 0x3f
|
|
|
|
for i := 96; i < 127; i++ {
|
|
v = in[inOff+i]
|
|
out[outOff+i] = (v << 6) | t
|
|
t = v >> 2
|
|
}
|
|
|
|
out[outOff+127] = t & 0x3f
|
|
}
|
|
}
|
|
|
|
func Unpad(in []byte, out []byte) {
|
|
// Assumes len(in)%128==0 and len(out)%127==0
|
|
if len(in) > int(MTTresh) {
|
|
mt(out, in, len(in), unpad)
|
|
return
|
|
}
|
|
|
|
unpad(out, in)
|
|
}
|
|
|
|
func unpad(out, in []byte) {
|
|
chunks := len(in) / 128
|
|
for chunk := 0; chunk < chunks; chunk++ {
|
|
inOffNext := chunk*128 + 1
|
|
outOff := chunk * 127
|
|
|
|
at := in[chunk*128]
|
|
|
|
for i := 0; i < 32; i++ {
|
|
next := in[i+inOffNext]
|
|
|
|
out[outOff+i] = at
|
|
//out[i] |= next << 8
|
|
|
|
at = next
|
|
}
|
|
|
|
out[outOff+31] |= at << 6
|
|
|
|
for i := 32; i < 64; i++ {
|
|
next := in[i+inOffNext]
|
|
|
|
out[outOff+i] = at >> 2
|
|
out[outOff+i] |= next << 6
|
|
|
|
at = next
|
|
}
|
|
|
|
out[outOff+63] ^= (at << 6) ^ (at << 4)
|
|
|
|
for i := 64; i < 96; i++ {
|
|
next := in[i+inOffNext]
|
|
|
|
out[outOff+i] = at >> 4
|
|
out[outOff+i] |= next << 4
|
|
|
|
at = next
|
|
}
|
|
|
|
out[outOff+95] ^= (at << 4) ^ (at << 2)
|
|
|
|
for i := 96; i < 127; i++ {
|
|
next := in[i+inOffNext]
|
|
|
|
out[outOff+i] = at >> 6
|
|
out[outOff+i] |= next << 2
|
|
|
|
at = next
|
|
}
|
|
}
|
|
}
|