Files
ritmex-bot/docs/lighter/poseidon_crypto-main/field/goldilocks/goldilocks_plonky2.go
T

155 lines
3.1 KiB
Go

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
// }