feat: 添加 Lighter 适配器及相关功能,支持 trailing stops 和新的交易逻辑

This commit is contained in:
discountry
2025-09-30 22:08:05 +08:00
parent e83bdfccf9
commit c8b0ab1c8e
101 changed files with 90621 additions and 3 deletions
@@ -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
}