mirror of
https://github.com/discountry/ritmex-bot.git
synced 2026-09-11 01:08:07 +00:00
feat: 添加 Lighter 适配器及相关功能,支持 trailing stops 和新的交易逻辑
This commit is contained in:
@@ -0,0 +1,499 @@
|
||||
package field
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
g "github.com/elliottech/poseidon_crypto/field/goldilocks"
|
||||
gFp5 "github.com/elliottech/poseidon_crypto/field/goldilocks_quintic_extension"
|
||||
|
||||
"math/big"
|
||||
"math/rand/v2"
|
||||
)
|
||||
|
||||
func TestBytes(t *testing.T) {
|
||||
e1 := g.Sample()
|
||||
|
||||
leBytes := g.ToLittleEndianBytes(e1)
|
||||
beBytes := e1.Bytes()
|
||||
for i := 0; i < g.Bytes; i++ {
|
||||
if beBytes[i] != leBytes[g.Bytes-i-1] {
|
||||
t.Fatalf("Big endian and little endian bytes are not reversed")
|
||||
}
|
||||
}
|
||||
|
||||
e1ReconstructedLE, _ := g.FromCanonicalLittleEndianBytes(leBytes)
|
||||
if !g.Equals(&e1, e1ReconstructedLE) {
|
||||
t.Fatalf("bytes do not match")
|
||||
}
|
||||
|
||||
r := rand.Uint64N(g.ORDER)
|
||||
|
||||
leBytesUint64 := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(leBytesUint64, r)
|
||||
|
||||
leBytesElem := g.ToLittleEndianBytes(g.FromUint64(r))
|
||||
for i := 0; i < 8; i++ {
|
||||
if leBytesUint64[i] != leBytesElem[i] {
|
||||
t.Fatalf("Little-endian bytes do not match at index %d: expected %x, got %x", i, leBytesUint64[i], leBytesElem[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBytesF(t *testing.T) {
|
||||
r := rand.Uint64N(g.ORDER)
|
||||
f := g.GoldilocksField(r)
|
||||
|
||||
rBytes := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(rBytes, r)
|
||||
|
||||
fBytes := g.ToLittleEndianBytesF(f)
|
||||
for i := 0; i < 8; i++ {
|
||||
if rBytes[i] != fBytes[i] {
|
||||
t.Fatalf("Little-endian bytes do not match at index %d: expected %x, got %x", i, rBytes[i], fBytes[i])
|
||||
}
|
||||
}
|
||||
|
||||
ff := g.FromCanonicalLittleEndianBytesF(fBytes)
|
||||
if ff != f {
|
||||
t.Fatalf("bytes do not match")
|
||||
}
|
||||
}
|
||||
|
||||
// Goldilocks field tests
|
||||
|
||||
// Inputs that covers several input ranges
|
||||
var inputs = []uint64{
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 2147483638, 2147483639, 2147483640, 2147483641, 2147483642, 2147483643, 2147483644, 2147483645, 2147483646, 2147483647, 2147483648, 2147483649,
|
||||
2147483650, 2147483651, 2147483652, 2147483653, 2147483654, 2147483655, 2147483656, 2147483657, 4294967286, 4294967287, 4294967288, 4294967289, 4294967290, 4294967291,
|
||||
4294967292, 4294967293, 4294967294, 4294967295, 4294967296, 4294967297, 4294967298, 4294967299, 4294967300, 4294967301, 4294967302, 4294967303, 4294967304, 4294967305,
|
||||
9223372036854775798, 9223372036854775799, 9223372036854775800, 9223372036854775801, 9223372036854775802, 9223372036854775803, 9223372036854775804, 9223372036854775805,
|
||||
9223372036854775806, 9223372036854775807, 9223372036854775808, 9223372036854775809, 9223372036854775810, 9223372036854775811, 9223372036854775812, 9223372036854775813,
|
||||
9223372036854775814, 9223372036854775815, 9223372036854775816, 9223372036854775817, 18446744069414584311, 18446744069414584312, 18446744069414584313, 18446744069414584314,
|
||||
18446744069414584315, 18446744069414584316, 18446744069414584317, 18446744069414584318, 18446744069414584319, 18446744069414584320,
|
||||
}
|
||||
|
||||
func NewBigInt(x uint64) *big.Int {
|
||||
return big.NewInt(0).SetUint64(x)
|
||||
}
|
||||
|
||||
func SumMod(x, y uint64) uint64 {
|
||||
sum := NewBigInt(x).Add(NewBigInt(x), NewBigInt(y))
|
||||
res := sum.Mod(sum, NewBigInt(g.ORDER))
|
||||
if !res.IsUint64() {
|
||||
panic("sum is not uint64")
|
||||
}
|
||||
return res.Uint64()
|
||||
}
|
||||
|
||||
func SubMod(x, y uint64) uint64 {
|
||||
sub := NewBigInt(x).Sub(NewBigInt(x), NewBigInt(y))
|
||||
res := sub.Mod(sub, NewBigInt(g.ORDER))
|
||||
if !res.IsUint64() {
|
||||
panic("difference is not uint64")
|
||||
}
|
||||
return res.Uint64()
|
||||
}
|
||||
|
||||
func MulMod(x, y uint64) uint64 {
|
||||
mul := NewBigInt(x).Mul(NewBigInt(x), NewBigInt(y))
|
||||
res := mul.Mod(mul, NewBigInt(g.ORDER))
|
||||
if !res.IsUint64() {
|
||||
panic("product is not uint64")
|
||||
}
|
||||
return res.Uint64()
|
||||
}
|
||||
|
||||
func NegMod(x uint64) uint64 {
|
||||
neg := NewBigInt(x).Neg(NewBigInt(x))
|
||||
res := neg.Mod(neg, NewBigInt(g.ORDER))
|
||||
if !res.IsUint64() {
|
||||
panic("negative number is not uint64")
|
||||
}
|
||||
return res.Uint64()
|
||||
}
|
||||
|
||||
func SquareMod(x uint64) uint64 {
|
||||
square := NewBigInt(x).Mul(NewBigInt(x), NewBigInt(x))
|
||||
res := square.Mod(square, NewBigInt(g.ORDER))
|
||||
if !res.IsUint64() {
|
||||
panic("square is not uint64")
|
||||
}
|
||||
return res.Uint64()
|
||||
}
|
||||
|
||||
func TestAddF(t *testing.T) {
|
||||
for _, lhs := range inputs {
|
||||
for _, rhs := range inputs {
|
||||
fLhs := g.GoldilocksField(lhs)
|
||||
fRhs := g.GoldilocksField(rhs)
|
||||
sum := g.AddF(fLhs, fRhs).ToCanonicalUint64()
|
||||
expected := SumMod(lhs, rhs)
|
||||
if sum != expected {
|
||||
t.Fatalf("Expected %d + %d = %d, but got %d", lhs, rhs, expected, sum)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubF(t *testing.T) {
|
||||
for _, lhs := range inputs {
|
||||
for _, rhs := range inputs {
|
||||
fLhs := g.GoldilocksField(lhs)
|
||||
fRhs := g.GoldilocksField(rhs)
|
||||
diff := g.SubF(fLhs, fRhs).ToCanonicalUint64()
|
||||
expected := SubMod(lhs, rhs)
|
||||
if diff != expected {
|
||||
t.Fatalf("Expected %d - %d = %d, but got %d", lhs, rhs, expected, diff)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMulF(t *testing.T) {
|
||||
for _, lhs := range inputs {
|
||||
for _, rhs := range inputs {
|
||||
fLhs := g.GoldilocksField(lhs)
|
||||
fRhs := g.GoldilocksField(rhs)
|
||||
mul := g.MulF(fLhs, fRhs).ToCanonicalUint64()
|
||||
expected := MulMod(lhs, rhs)
|
||||
if mul != expected {
|
||||
t.Fatalf("Expected %d * %d = %d, but got %d", lhs, rhs, expected, mul)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNegF(t *testing.T) {
|
||||
for _, lhs := range inputs {
|
||||
fLhs := g.GoldilocksField(lhs)
|
||||
neg := g.NegF(fLhs).ToCanonicalUint64()
|
||||
expected := NegMod(lhs)
|
||||
if neg != expected {
|
||||
t.Fatalf("Expected Neg(%d) = %d, but got %d", lhs, expected, neg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSquareF(t *testing.T) {
|
||||
for _, lhs := range inputs {
|
||||
fLhs := g.GoldilocksField(lhs)
|
||||
sqr := g.SquareF(fLhs).ToCanonicalUint64()
|
||||
expected := SquareMod(lhs)
|
||||
if sqr != expected {
|
||||
t.Fatalf("Expected (%d)^2 = %d, but got %d", lhs, expected, sqr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubFDoubleWraparound(t *testing.T) {
|
||||
/*
|
||||
let (a, b) = (F::from_canonical_u64((F::ORDER + 1u64) / 2u64), F::TWO);
|
||||
let x = a * b;
|
||||
assert_eq!(x, F::ONE);
|
||||
assert_eq!(F::ZERO - x, F::NEG_ONE);
|
||||
*/
|
||||
|
||||
a := g.GoldilocksField((g.ORDER + 1) / 2)
|
||||
b := g.GoldilocksField(2)
|
||||
x := g.MulF(a, b)
|
||||
if x.ToCanonicalUint64() != g.OneF().ToCanonicalUint64() {
|
||||
t.Fatalf("Expected a*b to be 1, but got %v", x)
|
||||
}
|
||||
if g.SubF(g.ZeroF(), x).ToCanonicalUint64() != g.NegOneF().ToCanonicalUint64() {
|
||||
t.Fatalf("Expected 0 - x to be -1, but got %v", g.SubF(g.ZeroF(), x))
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddFDoubleWraparound(t *testing.T) {
|
||||
/*
|
||||
let a = F::from_canonical_u64(u64::MAX - F::ORDER);
|
||||
let b = F::NEG_ONE;
|
||||
|
||||
let c = (a + a) + (b + b);
|
||||
let d = (a + b) + (a + b);
|
||||
|
||||
assert_eq!(c, d);
|
||||
*/
|
||||
|
||||
a := g.GoldilocksField(math.MaxUint64 - g.ORDER)
|
||||
b := g.NegOneF()
|
||||
|
||||
c := g.AddF(g.AddF(a, a), g.AddF(b, b))
|
||||
d := g.AddF(g.AddF(a, b), g.AddF(a, b))
|
||||
|
||||
if c.ToCanonicalUint64() != d.ToCanonicalUint64() {
|
||||
t.Fatalf("Expected c to be equal to d, but got %v and %v", c, d)
|
||||
}
|
||||
}
|
||||
|
||||
// Quintic extension tests
|
||||
|
||||
func TestQuinticExtensionAddSubMulSquare(t *testing.T) {
|
||||
val1 := gFp5.Element{
|
||||
g.FromUint64(0x1234567890ABCDEF),
|
||||
g.FromUint64(0x0FEDCBA987654321),
|
||||
g.FromUint64(0x1122334455667788),
|
||||
g.FromUint64(0x8877665544332211),
|
||||
g.FromUint64(0xAABBCCDDEEFF0011),
|
||||
}
|
||||
val2 := gFp5.Element{
|
||||
g.FromUint64(0xFFFFFFFFFFFFFFFF),
|
||||
g.FromUint64(0xFFFFFFFFFFFFFFFF),
|
||||
g.FromUint64(0xFFFFFFFFFFFFFFFF),
|
||||
g.FromUint64(0xFFFFFFFFFFFFFFFF),
|
||||
g.FromUint64(0xFFFFFFFFFFFFFFFF),
|
||||
}
|
||||
|
||||
add := gFp5.Add(val1, val2)
|
||||
expectedAdd := [5]uint64{1311768471589866989, 1147797413325783839, 1234605620731475846, 9833440832084189711, 12302652064957136911}
|
||||
for i := 0; i < 5; i++ {
|
||||
if add[i].Uint64() != expectedAdd[i] {
|
||||
t.Fatalf("Addition: Expected limb %d to be %x, but got %x", i, expectedAdd[i], add[i])
|
||||
}
|
||||
}
|
||||
|
||||
sub := gFp5.Sub(val1, val2)
|
||||
expectedSub := [5]uint64{1311768462999932401, 1147797404735849251, 1234605612141541258, 9833440823494255123, 12302652056367202323}
|
||||
for i := 0; i < 5; i++ {
|
||||
if sub[i].Uint64() != expectedSub[i] {
|
||||
t.Fatalf("Subtraction: Expected limb %d to be %x, but got %x", i, expectedSub[i], sub[i])
|
||||
}
|
||||
}
|
||||
|
||||
mul := gFp5.Mul(val1, val2)
|
||||
expectedMul := [5]uint64{12801331769143413385, 14031114708135177824, 4192851210753422088, 14031114723597060086, 4193451712464626164}
|
||||
for i := 0; i < 5; i++ {
|
||||
if mul[i].Uint64() != expectedMul[i] {
|
||||
t.Fatalf("Multiplication: Expected limb %d to be %x, but got %x", i, expectedMul[i], mul[i])
|
||||
}
|
||||
}
|
||||
|
||||
square := gFp5.Square(val1)
|
||||
expectedSquare := [5]uint64{
|
||||
2711468769317614959,
|
||||
15562737284369360677,
|
||||
48874032493986270,
|
||||
11211402278708723253,
|
||||
2864528669572451733,
|
||||
}
|
||||
for i := 0; i < 5; i++ {
|
||||
if square[i].Uint64() != expectedSquare[i] {
|
||||
t.Fatalf("Square: Expected limb %d to be %x, but got %x", i, expectedSquare[i], square[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestQuinticExtensionAddSubMulSquareF(t *testing.T) {
|
||||
val1 := gFp5.FromPlonky2GoldilocksField([]g.GoldilocksField{
|
||||
g.GoldilocksField(0x1234567890ABCDEF),
|
||||
g.GoldilocksField(0x0FEDCBA987654321),
|
||||
g.GoldilocksField(0x1122334455667788),
|
||||
g.GoldilocksField(0x8877665544332211),
|
||||
g.GoldilocksField(0xAABBCCDDEEFF0011),
|
||||
})
|
||||
val2 := gFp5.FromPlonky2GoldilocksField([]g.GoldilocksField{
|
||||
g.GoldilocksField(0xFFFFFFFFFFFFFFFF),
|
||||
g.GoldilocksField(0xFFFFFFFFFFFFFFFF),
|
||||
g.GoldilocksField(0xFFFFFFFFFFFFFFFF),
|
||||
g.GoldilocksField(0xFFFFFFFFFFFFFFFF),
|
||||
g.GoldilocksField(0xFFFFFFFFFFFFFFFF),
|
||||
})
|
||||
|
||||
add := gFp5.Add(val1, val2)
|
||||
expectedAdd := [5]uint64{1311768471589866989, 1147797413325783839, 1234605620731475846, 9833440832084189711, 12302652064957136911}
|
||||
for i := 0; i < 5; i++ {
|
||||
if add[i].Uint64() != expectedAdd[i] {
|
||||
t.Fatalf("Addition: Expected limb %d to be %x, but got %x", i, expectedAdd[i], add[i])
|
||||
}
|
||||
}
|
||||
|
||||
sub := gFp5.Sub(val1, val2)
|
||||
expectedSub := [5]uint64{1311768462999932401, 1147797404735849251, 1234605612141541258, 9833440823494255123, 12302652056367202323}
|
||||
for i := 0; i < 5; i++ {
|
||||
if sub[i].Uint64() != expectedSub[i] {
|
||||
t.Fatalf("Subtraction: Expected limb %d to be %x, but got %x", i, expectedSub[i], sub[i])
|
||||
}
|
||||
}
|
||||
|
||||
mul := gFp5.Mul(val1, val2)
|
||||
expectedMul := [5]uint64{12801331769143413385, 14031114708135177824, 4192851210753422088, 14031114723597060086, 4193451712464626164}
|
||||
for i := 0; i < 5; i++ {
|
||||
if mul[i].Uint64() != expectedMul[i] {
|
||||
t.Fatalf("Multiplication: Expected limb %d to be %x, but got %x", i, expectedMul[i], mul[i])
|
||||
}
|
||||
}
|
||||
|
||||
square := gFp5.Square(val1)
|
||||
expectedSquare := [5]uint64{
|
||||
2711468769317614959,
|
||||
15562737284369360677,
|
||||
48874032493986270,
|
||||
11211402278708723253,
|
||||
2864528669572451733,
|
||||
}
|
||||
for i := 0; i < 5; i++ {
|
||||
if square[i].Uint64() != expectedSquare[i] {
|
||||
t.Fatalf("Square: Expected limb %d to be %x, but got %x", i, expectedSquare[i], square[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepeatedFrobeniusgFp5(t *testing.T) {
|
||||
val := gFp5.Element{
|
||||
g.FromUint64(0x1234567890ABCDEF),
|
||||
g.FromUint64(0x0FEDCBA987654321),
|
||||
g.FromUint64(0x1122334455667788),
|
||||
g.FromUint64(0x8877665544332211),
|
||||
g.FromUint64(0xAABBCCDDEEFF0011),
|
||||
}
|
||||
|
||||
res := gFp5.RepeatedFrobenius(val, 1)
|
||||
|
||||
expected := [5]uint64{
|
||||
1311768467294899695,
|
||||
5234265561494296110,
|
||||
6204816484784411482,
|
||||
8858034429214283719,
|
||||
17855579289599571296,
|
||||
}
|
||||
for i := 0; i < 5; i++ {
|
||||
if res[i] != g.FromUint64(expected[i]) {
|
||||
t.Fatalf("Assertion failed at index %d: expected %d, got %d", i, expected[i], res[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTryInverse(t *testing.T) {
|
||||
val := gFp5.Element{
|
||||
g.FromUint64(0x1234567890ABCDEF),
|
||||
g.FromUint64(0x0FEDCBA987654321),
|
||||
g.FromUint64(0x1122334455667788),
|
||||
g.FromUint64(0x8877665544332211),
|
||||
g.FromUint64(0xAABBCCDDEEFF0011),
|
||||
}
|
||||
result := gFp5.InverseOrZero(val)
|
||||
|
||||
// Expected values
|
||||
expected := [5]uint64{
|
||||
10760985268447604442,
|
||||
1770001646280707407,
|
||||
826117924202660585,
|
||||
45414427571889187,
|
||||
8256636258983026155,
|
||||
}
|
||||
|
||||
for i, elem := range result.ToBasefieldArray() {
|
||||
if elem.Uint64() != expected[i] {
|
||||
t.Fatalf("Assertion failed at index %d: expected %d, got %d", i, expected[i], elem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestQuinticExtSgn0(t *testing.T) {
|
||||
if !gFp5.Sgn0(gFp5.Element{
|
||||
g.FromUint64(7146494650688613286),
|
||||
g.FromUint64(2524706331227574337),
|
||||
g.FromUint64(2805008444831673606),
|
||||
g.FromUint64(10342159727506097401),
|
||||
g.FromUint64(5582307593199735986),
|
||||
}) {
|
||||
t.Fatalf("Expected sign to be true, but got false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSqrtFunctions(t *testing.T) {
|
||||
x := gFp5.Element{
|
||||
g.FromUint64(17397692312497920520),
|
||||
g.FromUint64(4597259071399531684),
|
||||
g.FromUint64(15835726694542307225),
|
||||
g.FromUint64(16979717054676631815),
|
||||
g.FromUint64(12876043227925845432),
|
||||
}
|
||||
|
||||
expected := gFp5.Element{
|
||||
g.FromUint64(16260118390353633405),
|
||||
g.FromUint64(2204473665618140400),
|
||||
g.FromUint64(10421517006653550782),
|
||||
g.FromUint64(4618467884536173852),
|
||||
g.FromUint64(15556190572415033139),
|
||||
}
|
||||
|
||||
result, exists := gFp5.CanonicalSqrt(x)
|
||||
if !exists {
|
||||
t.Fatalf("Expected canonical sqrt to exist, but it does not")
|
||||
}
|
||||
|
||||
if !gFp5.Equals(result, expected) {
|
||||
t.Fatalf("Expected canonical sqrt to be %v, but got %v", expected, result)
|
||||
}
|
||||
|
||||
result2, exists2 := gFp5.Sqrt(x)
|
||||
if !exists2 {
|
||||
t.Fatalf("Expected sqrt to exist, but it does not")
|
||||
}
|
||||
|
||||
if !gFp5.Equals(result2, expected) {
|
||||
t.Fatalf("Expected sqrt to be %v, but got %v", expected, result2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSqrtNonExistent(t *testing.T) {
|
||||
_, exists := gFp5.Sqrt(gFp5.Element{
|
||||
g.FromUint64(3558249639744866495),
|
||||
g.FromUint64(2615658757916804776),
|
||||
g.FromUint64(14375546700029059319),
|
||||
g.FromUint64(16160052538060569780),
|
||||
g.FromUint64(8366525948816396307),
|
||||
})
|
||||
if exists {
|
||||
t.Fatalf("Expected sqrt not to exist, but it does")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLegendre(t *testing.T) {
|
||||
// Test zero
|
||||
zeroLegendre := gFp5.Legendre(gFp5.FP5_ZERO)
|
||||
if !zeroLegendre.IsZero() {
|
||||
t.Fatalf("Expected Legendre symbol of zero to be zero")
|
||||
}
|
||||
|
||||
// Test non-squares
|
||||
for i := 0; i < 32; i++ {
|
||||
var x gFp5.Element
|
||||
for {
|
||||
attempt := gFp5.Sample()
|
||||
if _, exists := gFp5.Sqrt(attempt); !exists {
|
||||
x = attempt
|
||||
break
|
||||
}
|
||||
}
|
||||
legendreSym := gFp5.Legendre(x)
|
||||
|
||||
negOne := g.NegOne()
|
||||
|
||||
if !negOne.Equal(&legendreSym) {
|
||||
t.Fatalf("Expected Legendre symbol of non-square to be -1, but got %v", legendreSym)
|
||||
}
|
||||
}
|
||||
|
||||
// Test squares
|
||||
for i := 0; i < 32; i++ {
|
||||
x := gFp5.Sample()
|
||||
square := gFp5.Square(x)
|
||||
legendreSym := gFp5.Legendre(square)
|
||||
|
||||
if !legendreSym.IsOne() {
|
||||
t.Fatalf("Expected Legendre symbol of square to be 1, but got %v", legendreSym)
|
||||
}
|
||||
}
|
||||
|
||||
// Test zero again
|
||||
x := gFp5.FP5_ZERO
|
||||
square := gFp5.Mul(x, x)
|
||||
legendreSym := gFp5.Legendre(square)
|
||||
if !legendreSym.IsZero() {
|
||||
t.Fatalf("Expected Legendre symbol of zero to be zero")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package goldilocks
|
||||
|
||||
//go:noescape
|
||||
func branchHint()
|
||||
@@ -0,0 +1,3 @@
|
||||
TEXT ·branchHint(SB),$0
|
||||
NOP
|
||||
RET
|
||||
@@ -0,0 +1,198 @@
|
||||
package goldilocks
|
||||
|
||||
// Partially wraps and extends the functionality of the goldilocks field package.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
g "github.com/consensys/gnark-crypto/field/goldilocks"
|
||||
)
|
||||
|
||||
type Element = g.Element
|
||||
|
||||
const Bytes = 8
|
||||
|
||||
func NewElement(value uint64) Element {
|
||||
return g.NewElement(value)
|
||||
}
|
||||
|
||||
func reverseBytes(b []byte) []byte {
|
||||
res := make([]byte, len(b))
|
||||
for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
|
||||
res[i], res[j] = b[j], b[i]
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func ArrayFromCanonicalLittleEndianBytes(in []byte) ([]Element, error) {
|
||||
missing := 8 - len(in)%8
|
||||
if missing == 8 {
|
||||
missing = 0
|
||||
}
|
||||
|
||||
ret := make([]Element, 0)
|
||||
for i := 0; i < len(in); {
|
||||
nextStart := i + 8
|
||||
|
||||
if nextStart > len(in) {
|
||||
nextStart = len(in)
|
||||
}
|
||||
|
||||
slice := make([]byte, 8)
|
||||
copy(slice[:], in[i:nextStart])
|
||||
if len(slice) < 8 {
|
||||
slice = append(slice, make([]byte, missing)...)
|
||||
}
|
||||
|
||||
elem, err := FromCanonicalLittleEndianBytes(slice)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to convert bytes to field element. bytes: %v, error: %w", slice, err)
|
||||
}
|
||||
ret = append(ret, *elem)
|
||||
i = nextStart
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func ToLittleEndianBytes(e ...Element) []byte {
|
||||
res := make([]byte, 0)
|
||||
for _, elem := range e {
|
||||
bytes := elem.Bytes()
|
||||
res = append(res, reverseBytes(bytes[:])...)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func FromCanonicalLittleEndianBytes(in []byte) (*Element, error) {
|
||||
elem := g.NewElement(0)
|
||||
err := elem.SetBytesCanonical(reverseBytes(in))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to convert bytes to field element: %w", err)
|
||||
}
|
||||
return &elem, nil
|
||||
}
|
||||
|
||||
func ArrayToLittleEndianBytes(e []Element) []byte {
|
||||
res := make([]byte, 0)
|
||||
for _, elem := range e {
|
||||
res = append(res, ToLittleEndianBytes(elem)...)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func ToString(e ...Element) string {
|
||||
res := ""
|
||||
for _, elem := range e {
|
||||
res += elem.String() + " "
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func FromBool(value bool) Element {
|
||||
if value {
|
||||
return One()
|
||||
}
|
||||
return Zero()
|
||||
}
|
||||
|
||||
func FromInt64Abs(value int64) Element {
|
||||
return FromUint64(uint64(value & 0x7FFFFFFFFFFFFFFF))
|
||||
}
|
||||
|
||||
func FromInt64(value int64) Element {
|
||||
elem := g.NewElement(0)
|
||||
elem.SetInt64(value)
|
||||
return elem
|
||||
}
|
||||
|
||||
func FromUint64(value uint64) Element {
|
||||
elem := g.NewElement(0)
|
||||
elem.SetUint64(value)
|
||||
return elem
|
||||
}
|
||||
|
||||
func FromUint32(value uint32) Element {
|
||||
return FromUint64(uint64(value))
|
||||
}
|
||||
|
||||
func Equals(a, b *Element) bool {
|
||||
return a.Equal(b)
|
||||
}
|
||||
|
||||
func Modulus() uint64 {
|
||||
return g.Modulus().Uint64()
|
||||
}
|
||||
|
||||
func Zero() Element {
|
||||
return g.NewElement(0)
|
||||
}
|
||||
|
||||
func One() Element {
|
||||
return g.NewElement(1)
|
||||
}
|
||||
|
||||
func Neg(e Element) Element {
|
||||
res := g.NewElement(0)
|
||||
res.Neg(&e)
|
||||
return res
|
||||
}
|
||||
|
||||
func NegOne() *Element {
|
||||
res := Neg(One())
|
||||
return &res
|
||||
}
|
||||
|
||||
func Sample() Element {
|
||||
elem := g.NewElement(0)
|
||||
elem.SetRandom()
|
||||
return elem
|
||||
}
|
||||
|
||||
func RandArray(count int) []Element {
|
||||
ret := make([]Element, count)
|
||||
for i := 0; i < count; i++ {
|
||||
ret[i] = Sample()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func Add(elems ...Element) Element {
|
||||
res := g.NewElement(0)
|
||||
for _, elem := range elems {
|
||||
res.Add(&res, &elem)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func Sub(a, b *Element) Element {
|
||||
res := g.NewElement(0)
|
||||
res.Sub(a, b)
|
||||
return res
|
||||
}
|
||||
|
||||
func Mul(elems ...*Element) Element {
|
||||
res := g.NewElement(1)
|
||||
for _, elem := range elems {
|
||||
res.Mul(&res, elem)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func Sqrt(elem *Element) *Element {
|
||||
elemCopy := DeepCopy(elem)
|
||||
return elemCopy.Sqrt(&elemCopy)
|
||||
}
|
||||
|
||||
// Powers starting from 1
|
||||
func Powers(e *Element, count int) []Element {
|
||||
ret := make([]Element, count)
|
||||
ret[0] = g.One()
|
||||
for i := 1; i < int(count); i++ {
|
||||
ret[i].Mul(&ret[i-1], e)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func DeepCopy(source *Element) Element {
|
||||
return Element{source[0]}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
package goldilocks
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"math/big"
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
type GoldilocksField uint64
|
||||
|
||||
const EPSILON = uint64((1 << 32) - 1)
|
||||
const ORDER = uint64(0xffffffff00000001)
|
||||
|
||||
var ORDER_BIG, _ = new(big.Int).SetString("0xffffffff00000001", 16)
|
||||
|
||||
func NonCannonicalGoldilocksField(x int64) GoldilocksField {
|
||||
if x < 0 {
|
||||
return NegF(GoldilocksField(-x))
|
||||
}
|
||||
|
||||
return GoldilocksField(x)
|
||||
}
|
||||
|
||||
func ZeroF() GoldilocksField {
|
||||
return 0
|
||||
}
|
||||
|
||||
func OneF() GoldilocksField {
|
||||
return 1
|
||||
}
|
||||
|
||||
func NegOneF() GoldilocksField {
|
||||
return GoldilocksField(ORDER - 1)
|
||||
}
|
||||
|
||||
func (z GoldilocksField) IsZero() bool {
|
||||
return z.ToCanonicalUint64() == 0
|
||||
}
|
||||
|
||||
func (z GoldilocksField) ToCanonicalUint64() uint64 {
|
||||
x := uint64(z)
|
||||
if x >= ORDER {
|
||||
x -= ORDER
|
||||
}
|
||||
|
||||
return x
|
||||
}
|
||||
|
||||
func AddF(lhs, rhs GoldilocksField) GoldilocksField {
|
||||
sum, over := bits.Add64(uint64(lhs), uint64(rhs), 0)
|
||||
sum, over = bits.Add64(sum, over*EPSILON, 0)
|
||||
if over == 1 {
|
||||
branchHint()
|
||||
sum += EPSILON // this can't overflow
|
||||
}
|
||||
|
||||
return GoldilocksField(sum)
|
||||
}
|
||||
|
||||
func DoubleF(lhs GoldilocksField) GoldilocksField {
|
||||
return AddF(lhs, lhs)
|
||||
}
|
||||
|
||||
func SubF(lhs, rhs GoldilocksField) GoldilocksField {
|
||||
diff, borrow := bits.Sub64(uint64(lhs), uint64(rhs), 0)
|
||||
diff, borrow = bits.Sub64(diff, borrow*EPSILON, 0)
|
||||
if borrow == 1 {
|
||||
branchHint()
|
||||
diff -= EPSILON // this can't underflow
|
||||
}
|
||||
|
||||
return GoldilocksField(diff)
|
||||
}
|
||||
|
||||
func MulF(lhs, rhs GoldilocksField) GoldilocksField {
|
||||
x_hi, x_lo := bits.Mul64(uint64(lhs), uint64(rhs))
|
||||
|
||||
x_hi_hi := x_hi >> 32
|
||||
x_hi_lo := x_hi & EPSILON
|
||||
|
||||
t0, borrow := bits.Sub64(x_lo, x_hi_hi, 0)
|
||||
if borrow == 1 {
|
||||
branchHint()
|
||||
t0 -= EPSILON
|
||||
}
|
||||
t1 := x_hi_lo * EPSILON
|
||||
|
||||
sum, over := bits.Add64(t0, t1, 0)
|
||||
t2 := sum + EPSILON*over
|
||||
return GoldilocksField(t2)
|
||||
}
|
||||
|
||||
func SquareF(x GoldilocksField) GoldilocksField {
|
||||
return MulF(x, x)
|
||||
}
|
||||
|
||||
func ExpPowerOf2(x GoldilocksField, n uint) GoldilocksField {
|
||||
z := x
|
||||
for i := uint(0); i < n; i++ {
|
||||
z = SquareF(z)
|
||||
}
|
||||
|
||||
return z
|
||||
}
|
||||
|
||||
func NegF(x GoldilocksField) GoldilocksField {
|
||||
z := GoldilocksField(0)
|
||||
if !x.IsZero() {
|
||||
z = GoldilocksField(ORDER - x.ToCanonicalUint64())
|
||||
}
|
||||
|
||||
return z
|
||||
}
|
||||
|
||||
func SampleF() GoldilocksField {
|
||||
rng, err := rand.Int(rand.Reader, ORDER_BIG)
|
||||
if err != nil {
|
||||
panic("failed to read random bytes into buffer")
|
||||
}
|
||||
return GoldilocksField(rng.Uint64())
|
||||
}
|
||||
|
||||
func ToLittleEndianBytesF(z GoldilocksField) []byte {
|
||||
res := make([]byte, Bytes)
|
||||
binary.LittleEndian.PutUint64(res, z.ToCanonicalUint64())
|
||||
return res
|
||||
}
|
||||
|
||||
func FromCanonicalLittleEndianBytesF(b []byte) GoldilocksField {
|
||||
return GoldilocksField(binary.LittleEndian.Uint64(b))
|
||||
}
|
||||
|
||||
// func (z *GoldilocksField) Inverse(x *GoldilocksField) *GoldilocksField {
|
||||
// if x.IsZero() {
|
||||
// z.SetZero()
|
||||
// return z
|
||||
// }
|
||||
|
||||
// var tmp *GoldilocksField
|
||||
|
||||
// t2 := *tmp.Square(x).Mul(tmp, x)
|
||||
// t3 := *tmp.Square(&t2).Mul(tmp, x)
|
||||
// t6 := *tmp.ExpPowerOf2(&t3, 3).Mul(tmp, &t3)
|
||||
// t12 := *tmp.ExpPowerOf2(&t6, 6).Mul(tmp, &t6)
|
||||
// t24 := *tmp.ExpPowerOf2(&t12, 12).Mul(tmp, &t12)
|
||||
// t30 := *tmp.ExpPowerOf2(&t24, 6).Mul(tmp, &t6)
|
||||
// t31 := *tmp.Square(&t30).Mul(tmp, x)
|
||||
// t63 := *tmp.ExpPowerOf2(&t31, 32).Mul(tmp, &t31)
|
||||
|
||||
// z.Square(&t63).Mul(z, x)
|
||||
|
||||
// return z
|
||||
// }
|
||||
+393
@@ -0,0 +1,393 @@
|
||||
package goldilocks_quintic_extension
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
g "github.com/elliottech/poseidon_crypto/field/goldilocks"
|
||||
)
|
||||
|
||||
type Element [5]g.Element
|
||||
|
||||
type NumericalElement [5]uint64
|
||||
|
||||
const Bytes = g.Bytes * 5
|
||||
|
||||
var (
|
||||
FP5_D = 5
|
||||
|
||||
FP5_ZERO = Element{g.Zero(), g.Zero(), g.Zero(), g.Zero(), g.Zero()}
|
||||
FP5_ONE = Element{g.One(), g.Zero(), g.Zero(), g.Zero(), g.Zero()}
|
||||
FP5_TWO = FromF(g.FromUint64(2))
|
||||
|
||||
FP5_W = g.FromUint64(3)
|
||||
FP5_DTH_ROOT = g.FromUint64(1041288259238279555)
|
||||
)
|
||||
|
||||
func (e *Element) ToString() string {
|
||||
return fmt.Sprintf("%d,%d,%d,%d,%d", e[0].Uint64(), e[1].Uint64(), e[2].Uint64(), e[3].Uint64(), e[4].Uint64())
|
||||
}
|
||||
|
||||
func (e Element) ToUint64Array() [5]uint64 {
|
||||
return [5]uint64{e[0].Uint64(), e[1].Uint64(), e[2].Uint64(), e[3].Uint64(), e[4].Uint64()}
|
||||
}
|
||||
|
||||
func gFp5FromUint64Array(arr [5]uint64) Element {
|
||||
return Element{g.FromUint64(arr[0]), g.FromUint64(arr[1]), g.FromUint64(arr[2]), g.FromUint64(arr[3]), g.FromUint64(arr[4])}
|
||||
}
|
||||
|
||||
func (e Element) ToBasefieldArray() [5]g.Element {
|
||||
return [5]g.Element{e[0], e[1], e[2], e[3], e[4]}
|
||||
}
|
||||
|
||||
func gFp5FromBasefieldArray(arr [5]g.Element) Element {
|
||||
return Element{arr[0], arr[1], arr[2], arr[3], arr[4]}
|
||||
}
|
||||
|
||||
func (e Element) ToLittleEndianBytes() []byte {
|
||||
elemBytes := [Bytes]byte{}
|
||||
for i, limb := range e {
|
||||
copy(elemBytes[i*g.Bytes:], g.ToLittleEndianBytes(limb))
|
||||
}
|
||||
return elemBytes[:]
|
||||
}
|
||||
|
||||
func FromCanonicalLittleEndianBytes(in []byte) (Element, error) {
|
||||
if len(in) != Bytes {
|
||||
return Element{}, fmt.Errorf("input bytes len should be 40 but is %d", len(in))
|
||||
}
|
||||
|
||||
elemBytesLittleEndian := [5][]byte{
|
||||
{in[0], in[1], in[2], in[3], in[4], in[5], in[6], in[7]},
|
||||
{in[8], in[9], in[10], in[11], in[12], in[13], in[14], in[15]},
|
||||
{in[16], in[17], in[18], in[19], in[20], in[21], in[22], in[23]},
|
||||
{in[24], in[25], in[26], in[27], in[28], in[29], in[30], in[31]},
|
||||
{in[32], in[33], in[34], in[35], in[36], in[37], in[38], in[39]},
|
||||
}
|
||||
|
||||
e1, err := g.FromCanonicalLittleEndianBytes(elemBytesLittleEndian[0])
|
||||
if err != nil {
|
||||
return Element{}, fmt.Errorf("failed to convert bytes to field element: %w", err)
|
||||
}
|
||||
e2, err := g.FromCanonicalLittleEndianBytes(elemBytesLittleEndian[1])
|
||||
if err != nil {
|
||||
return Element{}, fmt.Errorf("failed to convert bytes to field element: %w", err)
|
||||
}
|
||||
e3, err := g.FromCanonicalLittleEndianBytes(elemBytesLittleEndian[2])
|
||||
if err != nil {
|
||||
return Element{}, fmt.Errorf("failed to convert bytes to field element: %w", err)
|
||||
}
|
||||
e4, err := g.FromCanonicalLittleEndianBytes(elemBytesLittleEndian[3])
|
||||
if err != nil {
|
||||
return Element{}, fmt.Errorf("failed to convert bytes to field element: %w", err)
|
||||
}
|
||||
e5, err := g.FromCanonicalLittleEndianBytes(elemBytesLittleEndian[4])
|
||||
if err != nil {
|
||||
return Element{}, fmt.Errorf("failed to convert bytes to field element: %w", err)
|
||||
}
|
||||
|
||||
return Element{*e1, *e2, *e3, *e4, *e5}, nil
|
||||
}
|
||||
|
||||
func Sample() Element {
|
||||
arr := g.RandArray(5)
|
||||
return Element{arr[0], arr[1], arr[2], arr[3], arr[4]}
|
||||
}
|
||||
|
||||
func Equals(a, b Element) bool {
|
||||
return a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3] && a[4] == b[4]
|
||||
}
|
||||
|
||||
func IsZero(e Element) bool {
|
||||
return e[0].IsZero() && e[1].IsZero() && e[2].IsZero() && e[3].IsZero() && e[4].IsZero()
|
||||
}
|
||||
|
||||
func FromF(elem g.Element) Element {
|
||||
return Element{elem, g.Zero(), g.Zero(), g.Zero(), g.Zero()}
|
||||
}
|
||||
|
||||
func FromUint64(a uint64) Element {
|
||||
return Element{g.FromUint64(a), g.Zero(), g.Zero(), g.Zero(), g.Zero()}
|
||||
}
|
||||
|
||||
func FromUint64Array(elems [5]uint64) Element {
|
||||
return Element{
|
||||
g.FromUint64(elems[0]),
|
||||
g.FromUint64(elems[1]),
|
||||
g.FromUint64(elems[2]),
|
||||
g.FromUint64(elems[3]),
|
||||
g.FromUint64(elems[4]),
|
||||
}
|
||||
}
|
||||
|
||||
func Neg(e Element) Element {
|
||||
return Element{g.Neg(e[0]), g.Neg(e[1]), g.Neg(e[2]), g.Neg(e[3]), g.Neg(e[4])}
|
||||
}
|
||||
|
||||
func Add(a, b Element) Element {
|
||||
return Element{
|
||||
g.Add(a[0], b[0]),
|
||||
g.Add(a[1], b[1]),
|
||||
g.Add(a[2], b[2]),
|
||||
g.Add(a[3], b[3]),
|
||||
g.Add(a[4], b[4]),
|
||||
}
|
||||
}
|
||||
|
||||
func Sub(a, b Element) Element {
|
||||
return Element{
|
||||
g.Sub(&a[0], &b[0]),
|
||||
g.Sub(&a[1], &b[1]),
|
||||
g.Sub(&a[2], &b[2]),
|
||||
g.Sub(&a[3], &b[3]),
|
||||
g.Sub(&a[4], &b[4]),
|
||||
}
|
||||
}
|
||||
|
||||
func Mul(a, b Element) Element {
|
||||
w := FP5_W
|
||||
|
||||
a0b0 := g.Mul(&a[0], &b[0])
|
||||
a1b4 := g.Mul(&a[1], &b[4])
|
||||
a2b3 := g.Mul(&a[2], &b[3])
|
||||
a3b2 := g.Mul(&a[3], &b[2])
|
||||
a4b1 := g.Mul(&a[4], &b[1])
|
||||
added := g.Add(a1b4, a2b3, a3b2, a4b1)
|
||||
muld := g.Mul(&w, &added)
|
||||
c0 := g.Add(a0b0, muld)
|
||||
|
||||
a0b1 := g.Mul(&a[0], &b[1])
|
||||
a1b0 := g.Mul(&a[1], &b[0])
|
||||
a2b4 := g.Mul(&a[2], &b[4])
|
||||
a3b3 := g.Mul(&a[3], &b[3])
|
||||
a4b2 := g.Mul(&a[4], &b[2])
|
||||
added = g.Add(a2b4, a3b3, a4b2)
|
||||
muld = g.Mul(&w, &added)
|
||||
c1 := g.Add(a0b1, a1b0, muld)
|
||||
|
||||
a0b2 := g.Mul(&a[0], &b[2])
|
||||
a1b1 := g.Mul(&a[1], &b[1])
|
||||
a2b0 := g.Mul(&a[2], &b[0])
|
||||
a3b4 := g.Mul(&a[3], &b[4])
|
||||
a4b3 := g.Mul(&a[4], &b[3])
|
||||
added = g.Add(a3b4, a4b3)
|
||||
muld = g.Mul(&w, &added)
|
||||
c2 := g.Add(a0b2, a1b1, a2b0, muld)
|
||||
|
||||
a0b3 := g.Mul(&a[0], &b[3])
|
||||
a1b2 := g.Mul(&a[1], &b[2])
|
||||
a2b1 := g.Mul(&a[2], &b[1])
|
||||
a3b0 := g.Mul(&a[3], &b[0])
|
||||
a4b4 := g.Mul(&a[4], &b[4])
|
||||
muld = g.Mul(&w, &a4b4)
|
||||
c3 := g.Add(a0b3, a1b2, a2b1, a3b0, muld)
|
||||
|
||||
a0b4 := g.Mul(&a[0], &b[4])
|
||||
a1b3 := g.Mul(&a[1], &b[3])
|
||||
a2b2 := g.Mul(&a[2], &b[2])
|
||||
a3b1 := g.Mul(&a[3], &b[1])
|
||||
a4b0 := g.Mul(&a[4], &b[0])
|
||||
c4 := g.Add(a0b4, a1b3, a2b2, a3b1, a4b0)
|
||||
|
||||
return Element{c0, c1, c2, c3, c4}
|
||||
}
|
||||
|
||||
func Div(a, b Element) Element {
|
||||
bInv := InverseOrZero(b)
|
||||
if IsZero(bInv) {
|
||||
panic("division by zero")
|
||||
}
|
||||
return Mul(a, bInv)
|
||||
}
|
||||
|
||||
func ExpPowerOf2(x Element, power int) Element {
|
||||
res := Element{x[0], x[1], x[2], x[3], x[4]}
|
||||
for i := 0; i < power; i++ {
|
||||
res = Square(res)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func Square(a Element) Element {
|
||||
w := FP5_W
|
||||
double_w := g.Add(w, w)
|
||||
|
||||
a0s := g.Mul(&a[0], &a[0])
|
||||
a1a4 := g.Mul(&a[1], &a[4])
|
||||
a2a3 := g.Mul(&a[2], &a[3])
|
||||
added := g.Add(a1a4, a2a3)
|
||||
muld := g.Mul(&double_w, &added)
|
||||
c0 := g.Add(a0s, muld)
|
||||
|
||||
a0Double := g.Add(a[0], a[0])
|
||||
a0Doublea1 := g.Mul(&a0Double, &a[1])
|
||||
a2a4DoubleW := g.Mul(&a[2], &a[4], &double_w)
|
||||
a3a3w := g.Mul(&a[3], &a[3], &w)
|
||||
c1 := g.Add(a0Doublea1, a2a4DoubleW, a3a3w)
|
||||
|
||||
a0Doublea2 := g.Mul(&a0Double, &a[2])
|
||||
a1Square := g.Mul(&a[1], &a[1])
|
||||
a4a3DoubleW := g.Mul(&a[4], &a[3], &double_w)
|
||||
c2 := g.Add(a0Doublea2, a1Square, a4a3DoubleW)
|
||||
|
||||
a1Double := g.Add(a[1], a[1])
|
||||
a0Doublea3 := g.Mul(&a0Double, &a[3])
|
||||
a1Doublea2 := g.Mul(&a1Double, &a[2])
|
||||
a4SquareW := g.Mul(&a[4], &a[4], &w)
|
||||
c3 := g.Add(a0Doublea3, a1Doublea2, a4SquareW)
|
||||
|
||||
a0Doublea4 := g.Mul(&a0Double, &a[4])
|
||||
a1Doublea3 := g.Mul(&a1Double, &a[3])
|
||||
a2Square := g.Mul(&a[2], &a[2])
|
||||
c4 := g.Add(a0Doublea4, a1Doublea3, a2Square)
|
||||
|
||||
return Element{c0, c1, c2, c3, c4}
|
||||
}
|
||||
|
||||
func Triple(a Element) Element {
|
||||
three := g.FromUint64(3)
|
||||
return Element{
|
||||
g.Mul(&a[0], &three),
|
||||
g.Mul(&a[1], &three),
|
||||
g.Mul(&a[2], &three),
|
||||
g.Mul(&a[3], &three),
|
||||
g.Mul(&a[4], &three),
|
||||
}
|
||||
}
|
||||
|
||||
func Sqrt(x Element) (Element, bool) {
|
||||
v := ExpPowerOf2(x, 31)
|
||||
d := Mul(Mul(x, ExpPowerOf2(v, 32)), InverseOrZero(v))
|
||||
e := Frobenius(Mul(d, RepeatedFrobenius(d, 2)))
|
||||
_f := Square(e)
|
||||
|
||||
x1f4 := g.Mul(&x[1], &_f[4])
|
||||
x2f3 := g.Mul(&x[2], &_f[3])
|
||||
x3f2 := g.Mul(&x[3], &_f[2])
|
||||
x4f1 := g.Mul(&x[4], &_f[1])
|
||||
added := g.Add(x1f4, x2f3, x3f2, x4f1)
|
||||
three := g.FromUint64(3)
|
||||
muld := g.Mul(&three, &added)
|
||||
x0f0 := g.Mul(&x[0], &_f[0])
|
||||
_g := g.Add(x0f0, muld)
|
||||
s := g.Sqrt(&_g)
|
||||
if s == nil {
|
||||
return Element{}, false
|
||||
}
|
||||
|
||||
eInv := InverseOrZero(e)
|
||||
sFp5 := FromF(*s)
|
||||
|
||||
return Mul(sFp5, eInv), true
|
||||
}
|
||||
|
||||
func Sgn0(x Element) bool {
|
||||
sign := false
|
||||
zero := true
|
||||
for _, limb := range x {
|
||||
sign_i := (limb.Uint64() & 1) == 0
|
||||
zero_i := limb.IsZero()
|
||||
sign = sign || (zero && sign_i)
|
||||
zero = zero && zero_i
|
||||
}
|
||||
return sign
|
||||
}
|
||||
|
||||
func CanonicalSqrt(x Element) (Element, bool) {
|
||||
sqrtX, exists := Sqrt(x)
|
||||
if !exists {
|
||||
return Element{}, false
|
||||
}
|
||||
|
||||
if Sgn0(sqrtX) {
|
||||
return Neg(sqrtX), true
|
||||
}
|
||||
return sqrtX, true
|
||||
}
|
||||
|
||||
func ScalarMul(a Element, scalar g.Element) Element {
|
||||
return Element{
|
||||
g.Mul(&a[0], &scalar),
|
||||
g.Mul(&a[1], &scalar),
|
||||
g.Mul(&a[2], &scalar),
|
||||
g.Mul(&a[3], &scalar),
|
||||
g.Mul(&a[4], &scalar),
|
||||
}
|
||||
}
|
||||
|
||||
func Double(a Element) Element {
|
||||
return Add(a, a)
|
||||
}
|
||||
|
||||
func InverseOrZero(a Element) Element {
|
||||
if IsZero(a) {
|
||||
return FP5_ZERO
|
||||
}
|
||||
|
||||
d := Frobenius(a)
|
||||
e := Mul(d, Frobenius(d))
|
||||
f := Mul(e, RepeatedFrobenius(e, 2))
|
||||
|
||||
a0b0 := g.Mul(&a[0], &f[0])
|
||||
a1b4 := g.Mul(&a[1], &f[4])
|
||||
a2b3 := g.Mul(&a[2], &f[3])
|
||||
a3b2 := g.Mul(&a[3], &f[2])
|
||||
a4b1 := g.Mul(&a[4], &f[1])
|
||||
added := g.Add(a1b4, a2b3, a3b2, a4b1)
|
||||
muld := g.Mul(&FP5_W, &added)
|
||||
g := g.Add(a0b0, muld)
|
||||
|
||||
return ScalarMul(f, *g.Inverse(&g))
|
||||
}
|
||||
|
||||
func Frobenius(x Element) Element {
|
||||
return RepeatedFrobenius(x, 1)
|
||||
}
|
||||
|
||||
func RepeatedFrobenius(x Element, count int) Element {
|
||||
if count == 0 {
|
||||
return x
|
||||
} else if count >= FP5_D {
|
||||
return RepeatedFrobenius(x, count%FP5_D)
|
||||
}
|
||||
|
||||
z0 := FP5_DTH_ROOT
|
||||
for i := 1; i < count; i++ {
|
||||
z0 = g.Mul(&FP5_DTH_ROOT, &z0)
|
||||
}
|
||||
|
||||
res := Element{}
|
||||
for i, z := range g.Powers(&z0, FP5_D) {
|
||||
res[i] = g.Mul(&x[i], &z)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func Legendre(x Element) g.Element {
|
||||
frob1 := Frobenius(x)
|
||||
frob2 := Frobenius(frob1)
|
||||
|
||||
frob1TimesFrob2 := Mul(frob1, frob2)
|
||||
frob2Frob1TimesFrob2 := RepeatedFrobenius(frob1TimesFrob2, 2)
|
||||
|
||||
xrExt := Mul(Mul(x, frob1TimesFrob2), frob2Frob1TimesFrob2)
|
||||
xr := g.FromUint64(xrExt[0].Uint64())
|
||||
|
||||
xr31 := xr.Exp(xr, new(big.Int).SetUint64(1<<31))
|
||||
xr31InvOrZero := g.FromUint64(0)
|
||||
xr31InvOrZero = *xr31InvOrZero.Inverse(xr31)
|
||||
|
||||
xr63 := xr31.Exp(*xr31, new(big.Int).SetUint64(1<<32))
|
||||
|
||||
return g.Mul(xr63, &xr31InvOrZero)
|
||||
}
|
||||
|
||||
func FromPlonky2GoldilocksField(f []g.GoldilocksField) Element {
|
||||
return Element{
|
||||
g.NewElement(uint64(f[0])),
|
||||
g.NewElement(uint64(f[1])),
|
||||
g.NewElement(uint64(f[2])),
|
||||
g.NewElement(uint64(f[3])),
|
||||
g.NewElement(uint64(f[4])),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user