Split argon2 / blake2b code, use go 1.21 features

This commit is contained in:
DataHoarder 2024-04-11 17:50:09 +02:00
parent 5e7d8ea35f
commit 2c713700c1
Signed by: DataHoarder
SSH key fingerprint: SHA256:OLTRf6Fl87G52SiR7sWLGNzlJt4WOX+tfI2yxo0z7xk
7 changed files with 139 additions and 137 deletions

58
argon2.go Normal file
View file

@ -0,0 +1,58 @@
package randomx
import "golang.org/x/crypto/blake2b"
import (
_ "golang.org/x/crypto/argon2"
_ "unsafe"
)
// see reference configuration.h
// Cache size in KiB. Must be a power of 2.
const RANDOMX_ARGON_MEMORY = 262144
// Number of Argon2d iterations for Cache initialization.
const RANDOMX_ARGON_ITERATIONS = 3
// Number of parallel lanes for Cache initialization.
const RANDOMX_ARGON_LANES = 1
// Argon2d salt
const RANDOMX_ARGON_SALT = "RandomX\x03"
const ArgonSaltSize uint32 = 8 //sizeof("" RANDOMX_ARGON_SALT) - 1
const ArgonBlockSize uint32 = 1024
type argonBlock [128]uint64
const syncPoints = 4
//go:linkname argon2_initHash golang.org/x/crypto/argon2.initHash
func argon2_initHash(password, salt, key, data []byte, time, memory, threads, keyLen uint32, mode int) [blake2b.Size + 8]byte
//go:linkname argon2_initBlocks golang.org/x/crypto/argon2.initBlocks
func argon2_initBlocks(h0 *[blake2b.Size + 8]byte, memory, threads uint32) []argonBlock
//go:linkname argon2_processBlocks golang.org/x/crypto/argon2.processBlocks
func argon2_processBlocks(B []argonBlock, time, memory, threads uint32, mode int)
// argon2_buildBlocks From golang.org/x/crypto/argon2.deriveKey without last deriveKey call
func argon2_buildBlocks(password, salt, secret, data []byte, time, memory uint32, threads uint8, keyLen uint32) []argonBlock {
if time < 1 {
panic("argon2: number of rounds too small")
}
if threads < 1 {
panic("argon2: parallelism degree too low")
}
const mode = 0 /* argon2d */
h0 := argon2_initHash(password, salt, secret, data, time, memory, uint32(threads), keyLen, mode)
memory = memory / (syncPoints * uint32(threads)) * (syncPoints * uint32(threads))
if memory < 2*syncPoints*uint32(threads) {
memory = 2 * syncPoints * uint32(threads)
}
B := argon2_initBlocks(&h0, memory, uint32(threads))
argon2_processBlocks(B, time, memory, uint32(threads), mode)
return B
}

51
blake2b.go Normal file
View file

@ -0,0 +1,51 @@
package randomx
import (
"encoding/binary"
"golang.org/x/crypto/blake2b"
)
type Blake2Generator struct {
data [64]byte
dataindex int
allocRegIndex [8]int
allocRegisters [8]Register
}
func Init_Blake2Generator(key []byte, nonce uint32) *Blake2Generator {
var b Blake2Generator
b.dataindex = len(b.data)
if len(key) > 60 {
copy(b.data[:], key[0:60])
} else {
copy(b.data[:], key)
}
binary.LittleEndian.PutUint32(b.data[60:], nonce)
return &b
}
func (b *Blake2Generator) checkdata(bytesNeeded int) {
if b.dataindex+bytesNeeded > cap(b.data) {
//blake2b(data, sizeof(data), data, sizeof(data), nullptr, 0);
h := blake2b.Sum512(b.data[:])
copy(b.data[:], h[:])
b.dataindex = 0
}
}
func (b *Blake2Generator) GetByte() byte {
b.checkdata(1)
ret := b.data[b.dataindex]
//fmt.Printf("returning byte %02x\n", ret)
b.dataindex++
return ret
}
func (b *Blake2Generator) GetUint32() uint32 {
b.checkdata(4)
ret := binary.LittleEndian.Uint32(b.data[b.dataindex:])
b.dataindex += 4
return ret
}

View file

@ -1,7 +1,19 @@
package randomx
import (
"slices"
"unsafe"
)
type MemoryBlock [128]uint64
func (m MemoryBlock) getLine(addr uint64) []uint64 {
addr >>= 3
return m[addr : addr+8]
}
type Randomx_Cache struct {
Blocks []block
Blocks []MemoryBlock
Programs [RANDOMX_PROGRAM_COUNT]*SuperScalarProgram
}
@ -19,16 +31,19 @@ func (cache *Randomx_Cache) VM_Initialize() *VM {
}
}
func (cache *Randomx_Cache) Randomx_init_cache(key []byte) {
func (cache *Randomx_Cache) Init(key []byte) {
//fmt.Printf("appending null byte is not necessary but only done for testing")
kkey := append([]byte{}, key...)
//kkey = append(kkey,0)
//cache->initialize(cache, key, keySize);
cache.Blocks = buildBlocks(argon2d, kkey, []byte(RANDOMX_ARGON_SALT), []byte{}, []byte{}, RANDOMX_ARGON_ITERATIONS, RANDOMX_ARGON_MEMORY, RANDOMX_ARGON_LANES, 0)
argonBlocks := argon2_buildBlocks(kkey, []byte(RANDOMX_ARGON_SALT), []byte{}, []byte{}, RANDOMX_ARGON_ITERATIONS, RANDOMX_ARGON_MEMORY, RANDOMX_ARGON_LANES, 0)
memoryBlocks := unsafe.Slice((*MemoryBlock)(unsafe.Pointer(unsafe.SliceData(argonBlocks))), int(unsafe.Sizeof(argonBlock{}))/int(unsafe.Sizeof(MemoryBlock{}))*len(argonBlocks))
cache.Blocks = slices.Clone(memoryBlocks)
}
// fetch a 64 byte block in uint64 form
// GetMixBlock fetch a 64 byte block in uint64 form
func (cache *Randomx_Cache) GetMixBlock(addr uint64) []uint64 {
mask := CacheSize/CacheLineSize - 1
@ -36,12 +51,10 @@ func (cache *Randomx_Cache) GetMixBlock(addr uint64) []uint64 {
addr = (addr & mask) * CacheLineSize
block := addr / 1024
index_within_block := (addr % 1024) / 8
return cache.Blocks[block][index_within_block : index_within_block+8]
return cache.Blocks[block].getLine(addr % 1024)
}
func (cache *Randomx_Cache) InitDatasetItem(out *registerLine, itemnumber uint64) {
func (cache *Randomx_Cache) InitDatasetItem(out *registerLine, itemNumber uint64) {
const superscalarMul0 uint64 = 6364136223846793005
const superscalarAdd1 uint64 = 9298411001130361340
const superscalarAdd2 uint64 = 12065312585734608966
@ -53,10 +66,10 @@ func (cache *Randomx_Cache) InitDatasetItem(out *registerLine, itemnumber uint64
var rl registerLine
register_value := itemnumber
register_value := itemNumber
_ = register_value
rl[0] = (itemnumber + 1) * superscalarMul0
rl[0] = (itemNumber + 1) * superscalarMul0
rl[1] = rl[0] ^ superscalarAdd1
rl[2] = rl[0] ^ superscalarAdd2
rl[3] = rl[0] ^ superscalarAdd3
@ -85,14 +98,8 @@ func (cache *Randomx_Cache) InitDatasetItem(out *registerLine, itemnumber uint64
}
}
func (cache *Randomx_Cache) initDataset(start_item, end_item uint64) {
for itemnumber := start_item; itemnumber < end_item; itemnumber++ {
cache.InitDatasetItem(nil, itemnumber)
// dataset_index += CacheLineSize
//fmt.Printf("exiting dataset item\n")
break
func (cache *Randomx_Cache) initDataset(dataset []registerLine, startItem, endItem uint64) {
for itemNumber := startItem; itemNumber < endItem; itemNumber, dataset = itemNumber+1, dataset[1:] {
cache.InitDatasetItem(&dataset[0], itemNumber)
}
}

112
config.go
View file

@ -29,26 +29,6 @@ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package randomx
import "encoding/binary"
import "golang.org/x/crypto/blake2b"
import _ "unsafe"
import _ "golang.org/x/crypto/argon2"
// see reference configuration.h
// Cache size in KiB. Must be a power of 2.
const RANDOMX_ARGON_MEMORY = 262144
// Number of Argon2d iterations for Cache initialization.
const RANDOMX_ARGON_ITERATIONS = 3
// Number of parallel lanes for Cache initialization.
const RANDOMX_ARGON_LANES = 1
// Argon2d salt
const RANDOMX_ARGON_SALT = "RandomX\x03"
const ArgonSaltSize uint32 = 8 //sizeof("" RANDOMX_ARGON_SALT) - 1;
// Number of random Cache accesses per Dataset item. Minimum is 2.
const RANDOMX_CACHE_ACCESSES = 8
@ -87,7 +67,6 @@ const RANDOMX_JUMP_OFFSET = 8
const DATASETEXTRAITEMS = RANDOMX_DATASET_EXTRA_SIZE / RANDOMX_DATASET_ITEM_SIZE
const ArgonBlockSize uint32 = 1024
const SuperscalarMaxSize int = 3*RANDOMX_SUPERSCALAR_LATENCY + 2
const RANDOMX_DATASET_ITEM_SIZE uint64 = 64
const CacheLineSize uint64 = RANDOMX_DATASET_ITEM_SIZE
@ -130,94 +109,3 @@ const RANDOMX_FLAG_LARGE_PAGES = 2
func isZeroOrPowerOf2(x uint32) bool {
return (x & (x - 1)) == 0
}
type Blake2Generator struct {
data [64]byte
dataindex int
allocRegIndex [8]int
allocRegisters [8]Register
}
func Init_Blake2Generator(key []byte, nonce uint32) *Blake2Generator {
var b Blake2Generator
b.dataindex = len(b.data)
if len(key) > 60 {
copy(b.data[:], key[0:60])
} else {
copy(b.data[:], key)
}
binary.LittleEndian.PutUint32(b.data[60:], nonce)
return &b
}
func (b *Blake2Generator) checkdata(bytesNeeded int) {
if b.dataindex+bytesNeeded > cap(b.data) {
//blake2b(data, sizeof(data), data, sizeof(data), nullptr, 0);
h := blake2b.Sum512(b.data[:])
copy(b.data[:], h[:])
b.dataindex = 0
}
}
func (b *Blake2Generator) GetByte() byte {
b.checkdata(1)
ret := b.data[b.dataindex]
//fmt.Printf("returning byte %02x\n", ret)
b.dataindex++
return ret
}
func (b *Blake2Generator) GetUint32() uint32 {
b.checkdata(4)
ret := uint32(binary.LittleEndian.Uint32(b.data[b.dataindex:]))
//fmt.Printf("returning int32 %08x %08x\n", ret, binary.LittleEndian.Uint32(b.data[b.dataindex:]))
b.dataindex += 4
//fmt.Printf("returning int32 %08x\n", ret)
if ret == 0xc5dac17e {
// panic("exiting")
}
return ret
}
// some constants for argon
const (
argon2d = iota
argon2i
argon2id
)
type block [128]uint64
const syncPoints = 4
//go:linkname argon2_initHash golang.org/x/crypto/argon2.initHash
func argon2_initHash(password, salt, key, data []byte, time, memory, threads, keyLen uint32, mode int) [blake2b.Size + 8]byte
//go:linkname argon2_initBlocks golang.org/x/crypto/argon2.initBlocks
func argon2_initBlocks(h0 *[blake2b.Size + 8]byte, memory, threads uint32) []block
//go:linkname argon2_processBlocks golang.org/x/crypto/argon2.processBlocks
func argon2_processBlocks(B []block, time, memory, threads uint32, mode int)
func buildBlocks(mode int, password, salt, secret, data []byte, time, memory uint32, threads uint8, keyLen uint32) []block {
if time < 1 {
panic("argon2: number of rounds too small")
}
if threads < 1 {
panic("argon2: parallelism degree too low")
}
h0 := argon2_initHash(password, salt, secret, data, time, memory, uint32(threads), keyLen, mode)
memory = memory / (syncPoints * uint32(threads)) * (syncPoints * uint32(threads))
if memory < 2*syncPoints*uint32(threads) {
memory = 2 * syncPoints * uint32(threads)
}
B := argon2_initBlocks(&h0, memory, uint32(threads))
argon2_processBlocks(B, time, memory, uint32(threads), mode)
return B
//return extractKey(B, memory, uint32(threads), keyLen)
}

View file

@ -9,11 +9,9 @@ func (d *Randomx_DatasetLight) PrefetchDataset(address uint64) {
}
func (d *Randomx_DatasetLight) ReadDataset(address uint64, r *registerLine) {
itemnumber := address / CacheLineSize
var out registerLine
d.Cache.InitDatasetItem(&out, itemnumber)
d.Cache.InitDatasetItem(&out, address/CacheLineSize)
for i := range r {
r[i] ^= out[i]

2
go.mod
View file

@ -1,6 +1,6 @@
module git.gammaspectra.live/P2Pool/go-randomx
go 1.17
go 1.21
require golang.org/x/crypto v0.22.0

View file

@ -54,7 +54,7 @@ func Test_Randomx(t *testing.T) {
for ix, tt := range Tests {
t.Run(string(tt.key)+"_____"+string(tt.input), func(t *testing.T) {
c.Randomx_init_cache(tt.key)
c.Init(tt.key)
nonce := uint32(0) //uint32(len(key))
gen := Init_Blake2Generator(tt.key, nonce)
@ -82,7 +82,7 @@ func Benchmark_RandomX(b *testing.B) {
c := Randomx_alloc_cache(0)
c.Randomx_init_cache(tt.key)
c.Init(tt.key)
nonce := uint32(0) //uint32(len(key))
gen := Init_Blake2Generator(tt.key, nonce)