mirror of
https://github.com/discountry/ritmex-bot.git
synced 2026-09-11 17:28:08 +00:00
feat: 添加 Lighter 适配器及相关功能,支持 trailing stops 和新的交易逻辑
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
package signature
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
curve "github.com/elliottech/poseidon_crypto/curve/ecgfp5"
|
||||
g "github.com/elliottech/poseidon_crypto/field/goldilocks"
|
||||
gFp5 "github.com/elliottech/poseidon_crypto/field/goldilocks_quintic_extension"
|
||||
p2 "github.com/elliottech/poseidon_crypto/hash/poseidon2_goldilocks"
|
||||
)
|
||||
|
||||
type Signature struct {
|
||||
S curve.ECgFp5Scalar
|
||||
E curve.ECgFp5Scalar
|
||||
}
|
||||
|
||||
type NumericalSignature [10]uint64
|
||||
|
||||
func (s Signature) ToNumericalSignature() NumericalSignature {
|
||||
return NumericalSignature{
|
||||
s.S[0], s.S[1], s.S[2], s.S[3], s.S[4],
|
||||
s.E[0], s.E[1], s.E[2], s.E[3], s.E[4],
|
||||
}
|
||||
}
|
||||
|
||||
func (s Signature) DeepCopy() Signature {
|
||||
return Signature{
|
||||
S: s.S.DeepCopy(),
|
||||
E: s.E.DeepCopy(),
|
||||
}
|
||||
}
|
||||
|
||||
// (s little endian) || (e little endian)
|
||||
func (s Signature) ToBytes() []byte {
|
||||
sBytes := s.S.ToLittleEndianBytes()
|
||||
eBytes := s.E.ToLittleEndianBytes()
|
||||
res := make([]byte, 80)
|
||||
copy(res[:40], sBytes[:])
|
||||
copy(res[40:], eBytes[:])
|
||||
return res
|
||||
}
|
||||
|
||||
func SigFromBytes(b []byte) (Signature, error) {
|
||||
if len(b) != 80 {
|
||||
return ZERO_SIG, fmt.Errorf("signature length should be 80 but is %d", len(b))
|
||||
}
|
||||
|
||||
return Signature{
|
||||
S: curve.ScalarElementFromLittleEndianBytes(b[:40]),
|
||||
E: curve.ScalarElementFromLittleEndianBytes(b[40:]),
|
||||
}, nil
|
||||
}
|
||||
|
||||
var ZERO_SIG = Signature{
|
||||
S: curve.ZERO,
|
||||
E: curve.ZERO,
|
||||
}
|
||||
|
||||
var ONE_SK = curve.ONE
|
||||
|
||||
// Public key is actually an EC point (4 Fp5 elements), but it can be encoded as a single Fp5 element.
|
||||
func SchnorrPkFromSk(sk curve.ECgFp5Scalar) gFp5.Element {
|
||||
return curve.GENERATOR_ECgFp5Point.Mul(&sk).Encode()
|
||||
}
|
||||
|
||||
func SchnorrSignHashedMessage(hashedMsg gFp5.Element, sk curve.ECgFp5Scalar) Signature {
|
||||
// Sample random scalar `k` and compute `r = k * G`
|
||||
k := curve.SampleScalarCrypto()
|
||||
r := curve.GENERATOR_ECgFp5Point.Mul(&k).Encode()
|
||||
|
||||
// Compute `e = H(r || H(m))`, which is a scalar point
|
||||
preImage := make([]g.Element, 5+5)
|
||||
for i, elem := range r.ToBasefieldArray() {
|
||||
preImage[i] = elem
|
||||
}
|
||||
for i, elem := range hashedMsg.ToBasefieldArray() {
|
||||
preImage[i+5] = elem
|
||||
}
|
||||
|
||||
e := curve.FromGfp5(p2.HashToQuinticExtension(preImage))
|
||||
return Signature{
|
||||
S: k.Sub(*e.Mul(&sk)),
|
||||
E: e,
|
||||
}
|
||||
}
|
||||
|
||||
func SchnorrSignHashedMessage2(hashedMsg gFp5.Element, sk, k curve.ECgFp5Scalar) Signature {
|
||||
r := curve.GENERATOR_ECgFp5Point.Mul(&k).Encode()
|
||||
// Compute `e = H(r || H(m))`, which is a scalar point
|
||||
preImage := make([]g.Element, 5+5)
|
||||
for i, elem := range r.ToBasefieldArray() {
|
||||
preImage[i] = elem
|
||||
}
|
||||
for i, elem := range hashedMsg.ToBasefieldArray() {
|
||||
preImage[i+5] = elem
|
||||
}
|
||||
|
||||
e := curve.FromGfp5(p2.HashToQuinticExtension(preImage))
|
||||
return Signature{
|
||||
S: k.Sub(*e.Mul(&sk)),
|
||||
E: e,
|
||||
}
|
||||
}
|
||||
|
||||
func Validate(pubKey, hashedMsg, sig []byte) error {
|
||||
pk, err := gFp5.FromCanonicalLittleEndianBytes(pubKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert public key bytes to field element: %w", err)
|
||||
}
|
||||
hashedMsgElem, err := gFp5.FromCanonicalLittleEndianBytes(hashedMsg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert hashed message bytes to field element: %w", err)
|
||||
}
|
||||
s, err := SigFromBytes(sig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert signature bytes to Schnorr signature: %w", err)
|
||||
}
|
||||
|
||||
valid := IsSchnorrSignatureValid(&pk, &hashedMsgElem, s)
|
||||
if !valid {
|
||||
return fmt.Errorf("signature is invalid")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func IsSchnorrSignatureValid(pubKey, hashedMsg *gFp5.Element, sig Signature) bool {
|
||||
pubKeyWs, ok := curve.DecodeFp5AsWeierstrass(*pubKey)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
rV := curve.MulAdd2(curve.GENERATOR_WEIERSTRASS, pubKeyWs, sig.S, sig.E).Encode() // r_v = s*G + e*pk
|
||||
|
||||
preImage := make([]g.Element, 5+5)
|
||||
for i, elem := range rV.ToBasefieldArray() {
|
||||
preImage[i] = elem
|
||||
}
|
||||
for i, elem := range hashedMsg.ToBasefieldArray() {
|
||||
preImage[i+5] = elem
|
||||
}
|
||||
eV := curve.FromGfp5(p2.HashToQuinticExtension(preImage))
|
||||
|
||||
return eV.Equals(&sig.E) // e_v == e
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
package signature
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
curve "github.com/elliottech/poseidon_crypto/curve/ecgfp5"
|
||||
g "github.com/elliottech/poseidon_crypto/field/goldilocks"
|
||||
gFp5 "github.com/elliottech/poseidon_crypto/field/goldilocks_quintic_extension"
|
||||
p2 "github.com/elliottech/poseidon_crypto/hash/poseidon2_goldilocks"
|
||||
)
|
||||
|
||||
func TestSchnorrSignAndVerify(t *testing.T) {
|
||||
sk := curve.SampleScalarCrypto() // Sample a secret key
|
||||
msg := g.RandArray(244)
|
||||
hashedMsg := p2.HashToQuinticExtension(msg)
|
||||
k := curve.SampleScalarCrypto()
|
||||
|
||||
sig := SchnorrSignHashedMessage2(hashedMsg, sk, k)
|
||||
pk := SchnorrPkFromSk(sk)
|
||||
if !IsSchnorrSignatureValid(&pk, &hashedMsg, sig) {
|
||||
t.Fatalf("Signature is invalid")
|
||||
}
|
||||
}
|
||||
|
||||
func TestComparativeSchnorrSignAndVerify(t *testing.T) {
|
||||
sks := []curve.ECgFp5Scalar{
|
||||
curve.ECgFp5Scalar{
|
||||
12235002942052073545,
|
||||
1175977464658719998,
|
||||
8536934969147463310,
|
||||
6524687619313720391,
|
||||
2922072024880609112,
|
||||
},
|
||||
curve.ECgFp5Scalar{
|
||||
14609471659974493146,
|
||||
15558617123161593410,
|
||||
853367204868339037,
|
||||
17594253198278631904,
|
||||
368396584122947478,
|
||||
},
|
||||
curve.ECgFp5Scalar{
|
||||
846395111423676945, 1354180063821346280, 5751371120309175011, 4898038106472090654, 1076345918732914302,
|
||||
},
|
||||
}
|
||||
hashedMessages := []gFp5.Element{
|
||||
gFp5.Element{
|
||||
g.FromUint64(8398652514106806347),
|
||||
g.FromUint64(11069112711939986896),
|
||||
g.FromUint64(9732488227085561369),
|
||||
g.FromUint64(18076754337204438535),
|
||||
g.FromUint64(17155407358725346236),
|
||||
},
|
||||
gFp5.Element{
|
||||
g.FromUint64(14569490467507212064),
|
||||
g.FromUint64(2707063505563578676),
|
||||
g.FromUint64(7506743487465742335),
|
||||
g.FromUint64(12569771346154554175),
|
||||
g.FromUint64(4305083698940175790),
|
||||
},
|
||||
gFp5.Element{
|
||||
g.FromUint64(17529153479246803593),
|
||||
g.FromUint64(1743712677205511695),
|
||||
g.FromUint64(4834285972617397460),
|
||||
g.FromUint64(5486672566342530358),
|
||||
g.FromUint64(7254989001695704129),
|
||||
},
|
||||
}
|
||||
ks := []curve.ECgFp5Scalar{
|
||||
curve.ECgFp5Scalar{
|
||||
5245666847777449560,
|
||||
15178169970799106939,
|
||||
4403065012435293749,
|
||||
15306540389399388999,
|
||||
8935555081913173844,
|
||||
},
|
||||
curve.ECgFp5Scalar{
|
||||
1980123857560067020,
|
||||
10696795398834097509,
|
||||
3211831869376171671,
|
||||
6194822139276031840,
|
||||
3482023782412490864,
|
||||
},
|
||||
curve.ECgFp5Scalar{
|
||||
10299597990997564957, 8547298489021408803, 12250978550108858722, 5282281975236198197, 5328603554431393061,
|
||||
},
|
||||
}
|
||||
expectedSs := [][5]uint64{
|
||||
[5]uint64{
|
||||
6950590877883398434,
|
||||
17178336263794770543,
|
||||
11012823478139181320,
|
||||
16445091359523510936,
|
||||
5882925226143600273,
|
||||
},
|
||||
[5]uint64{
|
||||
15189311883262425203,
|
||||
16924634885527914505,
|
||||
11098200095411565797,
|
||||
11441434601417451505,
|
||||
2245797172600273048,
|
||||
},
|
||||
[5]uint64{
|
||||
1747989245728027396, 18083435619737379521, 18276259610811995786, 15101757397705334408, 5007814817019340642,
|
||||
},
|
||||
}
|
||||
expectedEs := [][5]uint64{
|
||||
[5]uint64{
|
||||
4544744459434870309,
|
||||
4180764085957612004,
|
||||
3024669018778978615,
|
||||
15433417688859446606,
|
||||
6775027260348937828,
|
||||
},
|
||||
[5]uint64{
|
||||
4905460437060282008,
|
||||
9275377852059362729,
|
||||
10383772785796962929,
|
||||
6858067464918579610,
|
||||
7078247668913970626,
|
||||
},
|
||||
[5]uint64{
|
||||
4911725746357568132, 12205663641120664338, 16433506899074513700, 14763562571101437023, 2547950465160283358,
|
||||
},
|
||||
}
|
||||
|
||||
for i := 0; i < len(sks); i++ {
|
||||
sig := SchnorrSignHashedMessage2(hashedMessages[i], sks[i], ks[i])
|
||||
for j := 0; j < 5; j++ {
|
||||
if sig.S[j] != expectedSs[i][j] {
|
||||
t.Fatalf("sig.S[%d]: Expected %d, but got %d", j, expectedSs[i][j], sig.S[j])
|
||||
}
|
||||
if sig.E[j] != expectedEs[i][j] {
|
||||
t.Fatalf("sig.E[%d]: Expected %d, but got %d", j, expectedEs[i][j], sig.E[j])
|
||||
}
|
||||
}
|
||||
|
||||
pk := SchnorrPkFromSk(sks[i])
|
||||
if !IsSchnorrSignatureValid(&pk, &hashedMessages[i], sig) {
|
||||
t.Fatalf("Signature is invalid")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBytes(t *testing.T) {
|
||||
sk := curve.SampleScalarCrypto() // Sample a secret key
|
||||
msg := g.RandArray(244) // Random message of 244 field elements (big)
|
||||
hashedMsg := p2.HashToQuinticExtension(msg)
|
||||
|
||||
sig := SchnorrSignHashedMessage(hashedMsg, sk)
|
||||
sig2, _ := SigFromBytes(sig.ToBytes())
|
||||
if !sig2.S.Equals(&sig.S) || !sig2.E.Equals(&sig.E) {
|
||||
t.Fatalf("bytes do not match")
|
||||
}
|
||||
|
||||
pk, _ := gFp5.FromCanonicalLittleEndianBytes(SchnorrPkFromSk(sk).ToLittleEndianBytes())
|
||||
|
||||
if err := Validate(pk.ToLittleEndianBytes(), hashedMsg.ToLittleEndianBytes(), sig2.ToBytes()); err != nil {
|
||||
t.Fatalf("Signature is invalid")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user