mirror of
https://github.com/discountry/ritmex-bot.git
synced 2026-09-11 09:18:08 +00:00
feat: 添加 Lighter 适配器及相关功能,支持 trailing stops 和新的交易逻辑
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
package poseidon_bn254
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/consensys/gnark-crypto/ecc/bn254/fr"
|
||||
"github.com/elliottech/poseidon_crypto/hash/poseidon_bn254/constants"
|
||||
)
|
||||
|
||||
// Number of full rounds
|
||||
const rf = 8
|
||||
|
||||
var alpha = big.NewInt(5)
|
||||
|
||||
// Number of partial rounds rounded up to nearest integer that divides by t in [2, 13]
|
||||
var rp = []int{56, 57, 56, 60, 60, 63, 64, 63, 60, 66, 60, 65, 70, 60, 64, 68}
|
||||
|
||||
// Round constants and matrices
|
||||
var (
|
||||
c, s [][]*fr.Element
|
||||
m, p [][][]*fr.Element
|
||||
)
|
||||
|
||||
func toElement(value string) *fr.Element {
|
||||
n, success := new(big.Int).SetString(value, 16)
|
||||
if !success {
|
||||
panic("Error parsing hex number")
|
||||
}
|
||||
e := fr.Element{0, 0, 0, 0}
|
||||
e.SetBigInt(n)
|
||||
return &e
|
||||
}
|
||||
|
||||
func init() {
|
||||
var size = len(rp)
|
||||
c = make([][]*fr.Element, size)
|
||||
s = make([][]*fr.Element, size)
|
||||
m = make([][][]*fr.Element, size)
|
||||
p = make([][][]*fr.Element, size)
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
// initialize round constants and matrices
|
||||
c[i] = make([]*fr.Element, len(constants.CStr[i]))
|
||||
s[i] = make([]*fr.Element, len(constants.SStr[i]))
|
||||
m[i] = make([][]*fr.Element, len(constants.MStr[i]))
|
||||
p[i] = make([][]*fr.Element, len(constants.PStr[i]))
|
||||
|
||||
for j := 0; j < len(c[i]); j++ {
|
||||
c[i][j] = toElement(constants.CStr[i][j])
|
||||
}
|
||||
for j := 0; j < len(s[i]); j++ {
|
||||
s[i][j] = toElement(constants.SStr[i][j])
|
||||
}
|
||||
for j := 0; j < len(m[i]); j++ {
|
||||
m[i][j] = make([]*fr.Element, len(constants.MStr[i][j]))
|
||||
for k := 0; k < len(m[i][j]); k++ {
|
||||
m[i][j][k] = toElement(constants.MStr[i][j][k])
|
||||
}
|
||||
}
|
||||
for j := 0; j < len(p[i]); j++ {
|
||||
p[i][j] = make([]*fr.Element, len(constants.PStr[i][j]))
|
||||
for k := 0; k < len(p[i][j]); k++ {
|
||||
p[i][j][k] = toElement(constants.PStr[i][j][k])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,208 @@
|
||||
package poseidon_bn254
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"hash"
|
||||
"math/big"
|
||||
|
||||
"github.com/consensys/gnark-crypto/ecc/bn254/fr"
|
||||
)
|
||||
|
||||
const (
|
||||
BlockSize = fr.Bytes // BlockSize size that poseidon consumes
|
||||
)
|
||||
|
||||
func zeroElement() *fr.Element {
|
||||
return &fr.Element{0, 0, 0, 0}
|
||||
}
|
||||
|
||||
func deepCopy(dst, src []*fr.Element) {
|
||||
if len(src) > len(dst) {
|
||||
panic("Cannot copy to a smaller destination")
|
||||
}
|
||||
for i := 0; i < len(src); i++ {
|
||||
v := *src[i]
|
||||
dst[i] = &v
|
||||
}
|
||||
}
|
||||
|
||||
// Add round constants
|
||||
func arc(state []*fr.Element, C []*fr.Element, t, offset int) {
|
||||
for i := 0; i < t; i++ {
|
||||
state[i].Add(state[i], C[offset+i])
|
||||
}
|
||||
}
|
||||
|
||||
// power 5 as s-box for full state
|
||||
func sbox(state []*fr.Element, t int) {
|
||||
for i := 0; i < t; i++ {
|
||||
state[i].Exp(*state[i], alpha)
|
||||
}
|
||||
}
|
||||
|
||||
// Matrix vector multiplication
|
||||
func mix(state []*fr.Element, M [][]*fr.Element, t int) []*fr.Element {
|
||||
newState := make([]*fr.Element, t)
|
||||
|
||||
for i := 0; i < t; i++ {
|
||||
newState[i] = zeroElement()
|
||||
for j := 0; j < t; j++ {
|
||||
newState[i].Add(newState[i], zeroElement().Mul(M[j][i], state[j]))
|
||||
}
|
||||
}
|
||||
return newState
|
||||
}
|
||||
|
||||
func permutation(state []*fr.Element) []*fr.Element {
|
||||
// Minimum length of state = nInput + nOutput = 2
|
||||
t := len(state)
|
||||
index := t - 2
|
||||
RP := rp[index]
|
||||
C := c[index]
|
||||
M := m[index]
|
||||
S := s[index]
|
||||
P := p[index]
|
||||
|
||||
// 1. Pre-step to the first-half of full rounds: add round constant for round=0
|
||||
arc(state, C, t, 0)
|
||||
|
||||
// 2. First-half of full rounds starting at roundNumber = 1 except last round
|
||||
for i := 0; i < rf/2-1; i++ {
|
||||
sbox(state, t)
|
||||
arc(state, C, t, (i+1)*t)
|
||||
state = mix(state, M, t)
|
||||
}
|
||||
|
||||
// 3. Last round of first-half of full rounds
|
||||
sbox(state, t)
|
||||
arc(state, C, t, (rf/2)*t)
|
||||
state = mix(state, P, t)
|
||||
|
||||
// 4. Partial rounds
|
||||
for i := 0; i < RP; i++ {
|
||||
state[0].Exp(*state[0], alpha)
|
||||
state[0].Add(state[0], C[(rf/2+1)*t+i])
|
||||
// S[i] is a vector of [t*2-1] elements where first t elements are used to compute state[0]
|
||||
// and the remaining elements starting at [t] are used to compute state[1,..,t-1]
|
||||
offset := (t*2 - 1) * i
|
||||
newState0 := zeroElement()
|
||||
for j := 0; j < len(state); j++ {
|
||||
newState0.Add(newState0, zeroElement().Mul(state[j], S[offset+j]))
|
||||
}
|
||||
offset += t - 1
|
||||
for k := 1; k < t; k++ {
|
||||
state[k].Add(state[k], zeroElement().Mul(state[0], S[offset+k]))
|
||||
}
|
||||
state[0] = newState0
|
||||
}
|
||||
|
||||
// 5. Second-half of full rounds except last round
|
||||
for i := 0; i < rf/2-1; i++ {
|
||||
sbox(state, t)
|
||||
arc(state, C, t, (rf/2+1)*t+RP+i*t)
|
||||
state = mix(state, M, t)
|
||||
}
|
||||
|
||||
// 6. Last round of the second-half of full rounds
|
||||
sbox(state, t)
|
||||
state = mix(state, M, t)
|
||||
return state
|
||||
}
|
||||
|
||||
func Poseidon(input ...*fr.Element) *fr.Element {
|
||||
inputLength := len(input)
|
||||
if inputLength == 0 {
|
||||
panic("No support for dummy input")
|
||||
}
|
||||
|
||||
const maxLength = 16
|
||||
state := make([]*fr.Element, maxLength+1)
|
||||
state[0] = zeroElement()
|
||||
startIndex := 0
|
||||
lastIndex := 0
|
||||
|
||||
// Make a hash chain of the input if its length > maxLength
|
||||
if inputLength > maxLength {
|
||||
count := inputLength / maxLength
|
||||
for i := 0; i < count; i++ {
|
||||
lastIndex = (i + 1) * maxLength
|
||||
deepCopy(state[1:], input[startIndex:lastIndex])
|
||||
state = permutation(state)
|
||||
startIndex = lastIndex
|
||||
}
|
||||
}
|
||||
|
||||
// For the remaining part of the input OR if 1 <= inputLength <= 16
|
||||
if lastIndex < inputLength {
|
||||
lastIndex = inputLength
|
||||
remainigLength := lastIndex - startIndex
|
||||
deepCopy(state[1:], input[startIndex:lastIndex])
|
||||
state = permutation(state[:remainigLength+1])
|
||||
}
|
||||
// Return capacity element 1
|
||||
return state[1]
|
||||
}
|
||||
|
||||
func PoseidonBytes(input ...[]byte) []byte {
|
||||
inputElements := make([]*fr.Element, len(input))
|
||||
for i, ele := range input {
|
||||
num := new(big.Int).SetBytes(ele)
|
||||
if num.Cmp(fr.Modulus()) >= 0 {
|
||||
panic("not support bytes bigger than modulus")
|
||||
}
|
||||
e := fr.Element{0, 0, 0, 0}
|
||||
e.SetBigInt(num)
|
||||
inputElements[i] = &e
|
||||
}
|
||||
res := Poseidon(inputElements...).Bytes()
|
||||
return res[:]
|
||||
}
|
||||
|
||||
type digest struct {
|
||||
h fr.Element
|
||||
data [][]byte // data to hash
|
||||
}
|
||||
|
||||
func NewPoseidon() hash.Hash {
|
||||
d := new(digest)
|
||||
d.Reset()
|
||||
return d
|
||||
}
|
||||
|
||||
// Reset resets the Hash to its initial state.
|
||||
func (d *digest) Reset() {
|
||||
d.data = nil
|
||||
d.h = fr.Element{0, 0, 0, 0}
|
||||
}
|
||||
|
||||
// Only receive byte slice less than fr.Modulus()
|
||||
func (d *digest) Write(p []byte) (n int, err error) {
|
||||
n = len(p)
|
||||
num := new(big.Int).SetBytes(p)
|
||||
if num.Cmp(fr.Modulus()) >= 0 {
|
||||
return 0, errors.New("not support bytes bigger than modulus")
|
||||
}
|
||||
d.data = append(d.data, p)
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (d *digest) Size() int {
|
||||
return BlockSize
|
||||
}
|
||||
|
||||
// BlockSize returns the number of bytes Sum will return.
|
||||
func (d *digest) BlockSize() int {
|
||||
return BlockSize
|
||||
}
|
||||
|
||||
// Sum appends the current hash to b and returns the resulting slice.
|
||||
// It does not change the underlying hash state.
|
||||
func (d *digest) Sum(b []byte) []byte {
|
||||
e := fr.Element{0, 0, 0, 0}
|
||||
e.SetBigInt(new(big.Int).SetBytes(PoseidonBytes(d.data...)))
|
||||
d.h = e
|
||||
d.data = nil // flush the data already hashed
|
||||
hash := d.h.Bytes()
|
||||
b = append(b, hash[:]...)
|
||||
return b
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
package poseidon_bn254_test
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/consensys/gnark-crypto/ecc/bn254/fr"
|
||||
"github.com/elliottech/poseidon_crypto/hash/poseidon_bn254"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func elementFromString(v string) *fr.Element {
|
||||
n, success := new(big.Int).SetString(v, 10)
|
||||
if !success {
|
||||
panic("Error parsing hex number")
|
||||
}
|
||||
var e fr.Element
|
||||
e.SetBigInt(n)
|
||||
return &e
|
||||
}
|
||||
|
||||
func elementFromStringHex(v string) *fr.Element {
|
||||
n, success := new(big.Int).SetString(v, 16)
|
||||
if !success {
|
||||
panic("Error parsing hex number")
|
||||
}
|
||||
var e fr.Element
|
||||
e.SetBigInt(n)
|
||||
return &e
|
||||
}
|
||||
|
||||
func TestPoseidon1(t *testing.T) {
|
||||
// WARNING: No test vector to compare with
|
||||
expectedHash := elementFromString("7764075183688725171230668857402392634761334547267776368103645048439717572548")
|
||||
length := 1
|
||||
inputs := make([]*fr.Element, length)
|
||||
for i := 0; i < length; i++ {
|
||||
e := fr.NewElement((uint64)(i + 1))
|
||||
inputs[i] = &e
|
||||
}
|
||||
actualHash := poseidon_bn254.Poseidon(inputs...)
|
||||
assert.True(t, actualHash.Equal(expectedHash), "%s != %s", actualHash, expectedHash)
|
||||
}
|
||||
|
||||
func TestPoseidon2(t *testing.T) {
|
||||
// WARNING: No test vector to compare with
|
||||
expectedHash := elementFromString("7142104613055408817911962100316808866448378443474503659992478482890339429929")
|
||||
length := 2
|
||||
inputs := make([]*fr.Element, length)
|
||||
for i := 0; i < length; i++ {
|
||||
e := fr.NewElement((uint64)(i + 1))
|
||||
inputs[i] = &e
|
||||
}
|
||||
actualHash := poseidon_bn254.Poseidon(inputs...)
|
||||
assert.True(t, actualHash.Equal(expectedHash), "%s != %s", actualHash, expectedHash)
|
||||
}
|
||||
|
||||
func TestPoseidon4(t *testing.T) {
|
||||
// WARNING: No test vector to compare with
|
||||
expectedHash := elementFromString("7817711165059374331357136443537800893307845083525445872661165200086166013245")
|
||||
length := 4
|
||||
inputs := make([]*fr.Element, length)
|
||||
for i := 0; i < length; i++ {
|
||||
e := fr.NewElement((uint64)(i + 1))
|
||||
inputs[i] = &e
|
||||
}
|
||||
actualHash := poseidon_bn254.Poseidon(inputs...)
|
||||
assert.True(t, actualHash.Equal(expectedHash), "%s != %s", actualHash, expectedHash)
|
||||
}
|
||||
|
||||
func TestPoseidon13(t *testing.T) {
|
||||
// WARNING: No test vector to compare with
|
||||
expectedHash := elementFromString("1709610050961943784828399921362905178787999827108026634048665681910636069934")
|
||||
length := 13
|
||||
inputs := make([]*fr.Element, length)
|
||||
for i := 0; i < length; i++ {
|
||||
e := fr.NewElement((uint64)(i + 1))
|
||||
inputs[i] = &e
|
||||
}
|
||||
actualHash := poseidon_bn254.Poseidon(inputs...)
|
||||
assert.True(t, actualHash.Equal(expectedHash), "%s != %s", actualHash, expectedHash)
|
||||
}
|
||||
|
||||
func TestPoseidon16(t *testing.T) {
|
||||
// WARNING: No test vector to compare with
|
||||
expectedHash := elementFromString("8319791455060392555425392842391403897548969645190976863995973180967774875286")
|
||||
length := 16
|
||||
inputs := make([]*fr.Element, length)
|
||||
for i := 0; i < length; i++ {
|
||||
e := fr.NewElement((uint64)(i + 1))
|
||||
inputs[i] = &e
|
||||
}
|
||||
actualHash := poseidon_bn254.Poseidon(inputs...)
|
||||
assert.True(t, actualHash.Equal(expectedHash), "%s != %s", actualHash, expectedHash)
|
||||
}
|
||||
|
||||
func TestPoseidon24(t *testing.T) {
|
||||
// WARNING: No test vector to compare with
|
||||
expectedHash := elementFromString("14281896993318141900551144554156181598834585543901557749703302979893059224887")
|
||||
length := 24
|
||||
inputs := make([]*fr.Element, length)
|
||||
for i := 0; i < length; i++ {
|
||||
e := fr.NewElement((uint64)(i + 1))
|
||||
inputs[i] = &e
|
||||
}
|
||||
actualHash := poseidon_bn254.Poseidon(inputs...)
|
||||
assert.True(t, actualHash.Equal(expectedHash), "%s != %s", actualHash, expectedHash)
|
||||
}
|
||||
|
||||
func TestPoseidon30(t *testing.T) {
|
||||
// WARNING: No test vector to compare with
|
||||
expectedHash := elementFromString("3706864405066113783363062549980271879113588784557216652303342540436728346372")
|
||||
length := 30
|
||||
inputs := make([]*fr.Element, length)
|
||||
for i := 0; i < length; i++ {
|
||||
e := fr.NewElement((uint64)(i + 1))
|
||||
inputs[i] = &e
|
||||
}
|
||||
actualHash := poseidon_bn254.Poseidon(inputs...)
|
||||
assert.True(t, actualHash.Equal(expectedHash), "%s != %s", actualHash, expectedHash)
|
||||
}
|
||||
|
||||
func TestPoseidon256(t *testing.T) {
|
||||
// WARNING: No test vector to compare with
|
||||
expectedHash := elementFromString("3889232958018785041730045800798978544000060048890444628344970190264245196615")
|
||||
length := 256
|
||||
inputs := make([]*fr.Element, length)
|
||||
for i := 0; i < length; i++ {
|
||||
e := fr.NewElement((uint64)(i + 1))
|
||||
inputs[i] = &e
|
||||
}
|
||||
actualHash := poseidon_bn254.Poseidon(inputs...)
|
||||
assert.True(t, actualHash.Equal(expectedHash), "%s != %s", actualHash, expectedHash)
|
||||
}
|
||||
|
||||
func TestConsistency(t *testing.T) {
|
||||
// Check whether Poseidon returns the same value for the same input
|
||||
// Test vector https://extgit.iaik.tugraz.at/krypto/hadeshash/-/blob/master/code/test_vectors.txt
|
||||
inputsStr := []string{"1", "2", "3", "4"}
|
||||
inputs := make([]*fr.Element, len(inputsStr))
|
||||
for i := 0; i < len(inputsStr); i++ {
|
||||
inputs[i] = elementFromString(inputsStr[i])
|
||||
}
|
||||
actualHash1 := poseidon_bn254.Poseidon(inputs...)
|
||||
actualHash2 := poseidon_bn254.Poseidon(inputs...)
|
||||
assert.True(t, actualHash1.Equal(actualHash2), "%s != %s", actualHash1, actualHash2)
|
||||
}
|
||||
|
||||
func TestPoseidonBytes(t *testing.T) {
|
||||
// Test vector https://extgit.iaik.tugraz.at/krypto/hadeshash/-/blob/master/code/test_vectors.txt
|
||||
expectedHash := elementFromStringHex("FCA49B798923AB0239DE1C9E7A4A9A2210312B6A2F616D18B5A87F9B628AE29")
|
||||
inputs := make([][]byte, 2)
|
||||
inputs[0] = make([]byte, 1)
|
||||
inputs[0][0] = 1
|
||||
inputs[1] = make([]byte, 1)
|
||||
inputs[1][0] = 2
|
||||
actualHash := poseidon_bn254.PoseidonBytes(inputs...)
|
||||
actualHashEle := fr.Element{0, 0, 0, 0}
|
||||
actualHashEle.SetBytes(actualHash)
|
||||
assert.True(t, actualHashEle.Equal(expectedHash), "%s != %s", actualHashEle, expectedHash)
|
||||
}
|
||||
|
||||
func TestDigest(t *testing.T) {
|
||||
expectedHash := elementFromStringHex("FCA49B798923AB0239DE1C9E7A4A9A2210312B6A2F616D18B5A87F9B628AE29")
|
||||
hFunc := poseidon_bn254.NewPoseidon()
|
||||
inputs := make([][]byte, 2)
|
||||
inputs[0] = make([]byte, 1)
|
||||
inputs[0][0] = 1
|
||||
inputs[1] = make([]byte, 1)
|
||||
inputs[1][0] = 2
|
||||
hFunc.Write(inputs[0])
|
||||
hFunc.Write(inputs[1])
|
||||
actualHash := hFunc.Sum(nil)
|
||||
actualHashEle := fr.Element{0, 0, 0, 0}
|
||||
actualHashEle.SetBytes(actualHash)
|
||||
assert.True(t, actualHashEle.Equal(expectedHash), "%s != %s", actualHashEle, expectedHash)
|
||||
|
||||
hFunc.Reset()
|
||||
bigNumber, _ := new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10)
|
||||
inputs[0] = bigNumber.Bytes()
|
||||
n, err := hFunc.Write(inputs[0])
|
||||
assert.EqualError(t, err, "not support bytes bigger than modulus")
|
||||
assert.Equal(t, n, 0)
|
||||
}
|
||||
Reference in New Issue
Block a user