From 1bdc34424c75abbcc724b23daf16f14c6bbc518c Mon Sep 17 00:00:00 2001 From: Jacob Jackson Date: Mon, 3 Oct 2022 19:17:42 +0000 Subject: [PATCH] basic edwards curve code --- .gitignore | 2 + README.md | 10 ++ cubic.go | 1 + ed25519.go | 80 +++++++-------- edwards_curve/edparams.go | 34 +++++++ edwards_curve/edpoint.go | 173 ++++++++++++++++++++++++++++++++ edwards_curve/edpoint_test.go | 183 ++++++++++++++++++++++++++++++++++ go.mod | 8 +- go.sum | 16 +++ 9 files changed, 465 insertions(+), 42 deletions(-) create mode 100644 edwards_curve/edparams.go create mode 100644 edwards_curve/edpoint.go create mode 100644 edwards_curve/edpoint_test.go diff --git a/.gitignore b/.gitignore index 66fd13c..fd45dc0 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ # Dependency directories (remove the comment below to include it) # vendor/ + +gnark-ed25519 diff --git a/README.md b/README.md index 7de5034..0a9118d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,12 @@ # gnark-ed25519 ed25519 implementation in Gnark + +To test: +``` +go test gnark-ed25519/edwards_curve +``` + +To build and run: +``` +go build gnark-ed25519 && ./gnark-ed25519 +``` diff --git a/cubic.go b/cubic.go index 89557e7..b4def71 100644 --- a/cubic.go +++ b/cubic.go @@ -21,6 +21,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/consensys/gnark/backend/groth16" + _ "gnark-ed25519/edwards_curve" ) // Circuit defines a simple circuit diff --git a/ed25519.go b/ed25519.go index 47b5612..0dbc218 100644 --- a/ed25519.go +++ b/ed25519.go @@ -14,43 +14,43 @@ package main -import ( - "fmt" - "os" - "crypto/ed25519" - "crypto/rand" - "github.com/consensys/gnark/std/math/emulated" -) - - - -func main() { - err := mainImpl() - if err != nil { - fmt.Println(err) - os.Exit(1) - } -} - -func mainImpl() error { - pubKey, privKey, err := ed25519.GenerateKey(rand.Reader) - fmt.Println(pubKey) - fmt.Println(privKey) - message := []byte("string") - sig := ed25519.Sign(privKey, message) - fmt.Println(sig) - verified := ed25519.Verify(pubKey, message, sig) - fmt.Println(verified) - - verifiedFalse := ed25519.Verify(pubKey, []byte("string1"), sig) - fmt.Println(verifiedFalse) - - ele := emulated.NewElement[emulated.BN254Fp](1) - fmt.Println(ele) - - if err != nil { - return err - } - return nil - -} +// import ( +// "fmt" +// "os" +// "crypto/ed25519" +// "crypto/rand" +// "github.com/consensys/gnark/std/math/emulated" +// ) + + + +// func main() { +// err := mainImpl() +// if err != nil { +// fmt.Println(err) +// os.Exit(1) +// } +// } + +// func mainImpl() error { +// pubKey, privKey, err := ed25519.GenerateKey(rand.Reader) +// fmt.Println(pubKey) +// fmt.Println(privKey) +// message := []byte("string") +// sig := ed25519.Sign(privKey, message) +// fmt.Println(sig) +// verified := ed25519.Verify(pubKey, message, sig) +// fmt.Println(verified) + +// verifiedFalse := ed25519.Verify(pubKey, []byte("string1"), sig) +// fmt.Println(verifiedFalse) + +// ele := emulated.NewElement[emulated.BN254Fp](1) +// fmt.Println(ele) + +// if err != nil { +// return err +// } +// return nil + +// } diff --git a/edwards_curve/edparams.go b/edwards_curve/edparams.go new file mode 100644 index 0000000..b1de598 --- /dev/null +++ b/edwards_curve/edparams.go @@ -0,0 +1,34 @@ +package edwards_curve + +import ( + "math/big" +) + +var ( + qEd25519, rEd25519 *big.Int +) + +func init() { + // https://neuromancer.sk/std/other/Ed25519 + qEd25519, _ = new(big.Int).SetString("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed", 16) + n, _ := new(big.Int).SetString("1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed", 16) + // TODO: is this ok? + // h := big.NewInt(8) + // rEd25519 = new(big.Int).Mul(n, h) + rEd25519 = n +} + +type Ed25519 struct{} + +func (fp Ed25519) NbLimbs() uint { return 4 } +func (fp Ed25519) BitsPerLimb() uint { return 64 } +func (fp Ed25519) IsPrime() bool { return true } +func (fp Ed25519) Modulus() *big.Int { return qEd25519 } + +type Ed25519Scalars struct{} + +func (fp Ed25519Scalars) NbLimbs() uint { return 4 } +func (fp Ed25519Scalars) BitsPerLimb() uint { return 64 } +func (fp Ed25519Scalars) IsPrime() bool { return true } +func (fp Ed25519Scalars) Modulus() *big.Int { return rEd25519 } + diff --git a/edwards_curve/edpoint.go b/edwards_curve/edpoint.go new file mode 100644 index 0000000..7ee6543 --- /dev/null +++ b/edwards_curve/edpoint.go @@ -0,0 +1,173 @@ +package edwards_curve + +import ( + "fmt" + "math/big" + + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/math/emulated" +) + +func New[T, S emulated.FieldParams](api frontend.API) (*Curve[T, S], error) { + var t T + var s S + var gxb, gyb *big.Int + var A, D *big.Int + _, is_25519_t := any(t).(Ed25519) + _, is_25519_s := any(s).(Ed25519Scalars) + if is_25519_t && is_25519_s { + // https://neuromancer.sk/std/other/Ed25519 + gxb = newBigInt("216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A") + gyb = newBigInt("6666666666666666666666666666666666666666666666666666666666666658") + A = newBigInt("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec") + D = newBigInt("52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3") + } else { + return nil, fmt.Errorf("unknown curve") + } + return newCurve[T, S]( + api, + emulated.NewElement[T](A), + emulated.NewElement[T](D), + emulated.NewElement[T](gxb), + emulated.NewElement[T](gyb)) +} + +func newBigInt(s string) *big.Int { + result, success := new(big.Int).SetString(s, 16) + if !success { + panic("invalid bigint") + } + return result +} + +// TODO: could also have a type constraint for curve parameters (fields, +// equation and generator). But for now we don't do arbitrary curves. + +type Curve[T, S emulated.FieldParams] struct { + A emulated.Element[T] + D emulated.Element[T] + + // api is the native api, we construct it ourselves to be sure + api frontend.API + // baseApi is the api for point operations + baseApi frontend.API + // scalarApi is the api for scalar operations + scalarApi frontend.API + + g AffinePoint[T] +} + +func (c *Curve[T, S]) Generator() AffinePoint[T] { + return c.g +} + +func newCurve[T, S emulated.FieldParams](api frontend.API, A, D, Gx, Gy emulated.Element[T]) (*Curve[T, S], error) { + ba, err := emulated.NewField[T](api) + if err != nil { + return nil, fmt.Errorf("new base api: %w", err) + } + sa, err := emulated.NewField[S](api) + if err != nil { + return nil, fmt.Errorf("new scalar api: %w", err) + } + return &Curve[T, S]{ + A: A, + D: D, + api: api, + baseApi: ba, + scalarApi: sa, + g: AffinePoint[T]{ + X: Gx, + Y: Gy, + }, + }, nil +} + +type AffinePoint[T emulated.FieldParams] struct { + X, Y emulated.Element[T] +} + +func (c *Curve[T, S]) Neg(p AffinePoint[T]) AffinePoint[T] { + return AffinePoint[T]{ + X: p.X, + Y: c.baseApi.Neg(p.Y).(emulated.Element[T]), + } +} + +func (c *Curve[T, S]) AssertIsEqual(p, q AffinePoint[T]) { + c.baseApi.AssertIsEqual(p.X, q.X) + c.baseApi.AssertIsEqual(p.Y, q.Y) +} + +func (c *Curve[T, S]) AssertIsOnCurve(p AffinePoint[T]) { + xx := c.baseApi.Mul(p.X, p.X) + yy := c.baseApi.Mul(p.Y, p.Y) + fmt.Println(xx) + fmt.Println(c.A) + axx := c.baseApi.Mul(xx, c.A) + lhs := c.baseApi.Add(axx, yy) + + dxx := c.baseApi.Mul(xx, c.D) + dxxyy := c.baseApi.Mul(dxx, yy) + rhs := c.baseApi.Add(dxxyy, 1) + + c.baseApi.AssertIsEqual(lhs, rhs) +} + +// func (c *Curve[T, S]) Add(q, r AffinePoint[T]) AffinePoint[T] { +// // compute lambda = (p1.y-p.y)/(p1.x-p.x) +// lambda := c.baseApi.DivUnchecked(c.baseApi.Sub(r.Y, q.Y), c.baseApi.Sub(r.X, q.X)) + +// // xr = lambda**2-p.x-p1.x +// xr := c.baseApi.Sub(c.baseApi.Mul(lambda, lambda), c.baseApi.Add(q.X, r.X)) + +// // p.y = lambda(p.x-xr) - p.y +// py := c.baseApi.Sub(c.baseApi.Mul(lambda, c.baseApi.Sub(q.X, xr)), q.Y) + +// return AffinePoint[T]{ +// X: xr.(emulated.Element[T]), +// Y: py.(emulated.Element[T]), +// } +// } + +// func (c *Curve[T, S]) Double(p AffinePoint[T]) AffinePoint[T] { + +// // compute lambda = (3*p1.x**2+a)/2*p1.y, here we assume a=0 (j invariant 0 curve) +// lambda := c.baseApi.DivUnchecked(c.baseApi.Mul(p.X, p.X, 3), c.baseApi.Mul(p.Y, 2)) + +// // xr = lambda**2-p1.x-p1.x +// xr := c.baseApi.Sub(c.baseApi.Mul(lambda, lambda), c.baseApi.Mul(p.X, 2)) + +// // p.y = lambda(p.x-xr) - p.y +// py := c.baseApi.Sub(c.baseApi.Mul(lambda, c.baseApi.Sub(p.X, xr)), p.Y) + +// return AffinePoint[T]{ +// X: xr.(emulated.Element[T]), +// Y: py.(emulated.Element[T]), +// } +// } + +func (c *Curve[T, S]) Select(b frontend.Variable, p, q AffinePoint[T]) AffinePoint[T] { + x := c.baseApi.Select(b, p.X, q.X) + y := c.baseApi.Select(b, p.Y, q.Y) + return AffinePoint[T]{ + X: x.(emulated.Element[T]), + Y: y.(emulated.Element[T]), + } +} + +// func (c *Curve[T, S]) ScalarMul(p AffinePoint[T], s emulated.Element[S]) AffinePoint[T] { +// res := p +// acc := c.Double(p) + +// sBits := c.scalarApi.ToBinary(s) +// for i := 1; i < len(sBits); i++ { +// tmp := c.Add(res, acc) +// res = c.Select(sBits[i], tmp, res) +// acc = c.Double(acc) +// } + +// tmp := c.Add(res, c.Neg(p)) +// res = c.Select(sBits[0], res, tmp) +// return res +// } diff --git a/edwards_curve/edpoint_test.go b/edwards_curve/edpoint_test.go new file mode 100644 index 0000000..760216a --- /dev/null +++ b/edwards_curve/edpoint_test.go @@ -0,0 +1,183 @@ +package edwards_curve + +import ( + "testing" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/math/emulated" + "github.com/consensys/gnark/test" + // "github.com/ethereum/go-ethereum/crypto/secp256k1" +) + +type OnCurveTest[T, S emulated.FieldParams] struct { + P AffinePoint[T] +} + +func (c *OnCurveTest[T, S]) Define(api frontend.API) error { + cr, err := New[T, S](api) + if err != nil { + return err + } + cr.AssertIsOnCurve(c.P) + return nil +} + +func TestGenerator(t *testing.T) { + assert := test.NewAssert(t) + circuit := OnCurveTest[Ed25519, Ed25519Scalars]{} + witness := OnCurveTest[Ed25519, Ed25519Scalars]{ + P: AffinePoint[Ed25519]{ + X: emulated.NewElement[Ed25519](newBigInt("216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A")), + Y: emulated.NewElement[Ed25519](newBigInt("6666666666666666666666666666666666666666666666666666666666666658")), + }, + } + err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) + assert.NoError(err) +} + +var testCurve = ecc.BN254 + +// type NegTest[T, S emulated.FieldParams] struct { +// P, Q AffinePoint[T] +// } + +// func (c *NegTest[T, S]) Define(api frontend.API) error { +// cr, err := New[T, S](api) +// if err != nil { +// return err +// } +// res := cr.Neg(c.P) +// cr.AssertIsEqual(res, c.Q) +// return nil +// } + +// func TestNeg(t *testing.T) { +// assert := test.NewAssert(t) +// secpCurve := secp256k1.S256() +// yn := new(big.Int).Sub(secpCurve.P, secpCurve.Gy) +// circuit := NegTest[emulated.Secp256k1, emulated.Secp256k1Scalars]{} +// witness := NegTest[emulated.Secp256k1, emulated.Secp256k1Scalars]{ +// P: AffinePoint[emulated.Secp256k1]{ +// X: emulated.NewElement[emulated.Secp256k1](secpCurve.Gx), +// Y: emulated.NewElement[emulated.Secp256k1](secpCurve.Gy), +// }, +// Q: AffinePoint[emulated.Secp256k1]{ +// X: emulated.NewElement[emulated.Secp256k1](secpCurve.Gx), +// Y: emulated.NewElement[emulated.Secp256k1](yn), +// }, +// } +// err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) +// assert.NoError(err) +// } + +// type AddTest[T, S emulated.FieldParams] struct { +// P, Q, R AffinePoint[T] +// } + +// func (c *AddTest[T, S]) Define(api frontend.API) error { +// cr, err := New[T, S](api) +// if err != nil { +// return err +// } +// res := cr.Add(c.P, c.Q) +// cr.AssertIsEqual(res, c.R) +// return nil +// } + +// func TestAdd(t *testing.T) { +// assert := test.NewAssert(t) +// secpCurve := secp256k1.S256() +// xd, yd := secpCurve.Double(secpCurve.Gx, secpCurve.Gy) +// xa, ya := secpCurve.Add(xd, yd, secpCurve.Gx, secpCurve.Gy) +// circuit := AddTest[emulated.Secp256k1, emulated.Secp256k1Scalars]{} +// witness := AddTest[emulated.Secp256k1, emulated.Secp256k1Scalars]{ +// P: AffinePoint[emulated.Secp256k1]{ +// X: emulated.NewElement[emulated.Secp256k1](secpCurve.Gx), +// Y: emulated.NewElement[emulated.Secp256k1](secpCurve.Gy), +// }, +// Q: AffinePoint[emulated.Secp256k1]{ +// X: emulated.NewElement[emulated.Secp256k1](xd), +// Y: emulated.NewElement[emulated.Secp256k1](yd), +// }, +// R: AffinePoint[emulated.Secp256k1]{ +// X: emulated.NewElement[emulated.Secp256k1](xa), +// Y: emulated.NewElement[emulated.Secp256k1](ya), +// }, +// } +// err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) +// assert.NoError(err) +// } + +// type DoubleTest[T, S emulated.FieldParams] struct { +// P, Q AffinePoint[T] +// } + +// func (c *DoubleTest[T, S]) Define(api frontend.API) error { +// cr, err := New[T, S](api) +// if err != nil { +// return err +// } +// res := cr.Double(c.P) +// cr.AssertIsEqual(res, c.Q) +// return nil +// } + +// func TestDouble(t *testing.T) { +// assert := test.NewAssert(t) +// secpCurve := secp256k1.S256() +// xd, yd := secpCurve.Double(secpCurve.Gx, secpCurve.Gy) +// circuit := DoubleTest[emulated.Secp256k1, emulated.Secp256k1Scalars]{} +// witness := DoubleTest[emulated.Secp256k1, emulated.Secp256k1Scalars]{ +// P: AffinePoint[emulated.Secp256k1]{ +// X: emulated.NewElement[emulated.Secp256k1](secpCurve.Gx), +// Y: emulated.NewElement[emulated.Secp256k1](secpCurve.Gy), +// }, +// Q: AffinePoint[emulated.Secp256k1]{ +// X: emulated.NewElement[emulated.Secp256k1](xd), +// Y: emulated.NewElement[emulated.Secp256k1](yd), +// }, +// } +// err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) +// assert.NoError(err) +// } + +// type ScalarMulTest[T, S emulated.FieldParams] struct { +// P, Q AffinePoint[T] +// S emulated.Element[S] +// } + +// func (c *ScalarMulTest[T, S]) Define(api frontend.API) error { +// cr, err := New[T, S](api) +// if err != nil { +// return err +// } +// res := cr.ScalarMul(c.P, c.S) +// cr.AssertIsEqual(res, c.Q) +// return nil +// } + +// func TestScalarMul(t *testing.T) { +// assert := test.NewAssert(t) +// secpCurve := secp256k1.S256() +// s, ok := new(big.Int).SetString("44693544921776318736021182399461740191514036429448770306966433218654680512345", 10) +// assert.True(ok) +// sx, sy := secpCurve.ScalarMult(secpCurve.Gx, secpCurve.Gy, s.Bytes()) + +// circuit := ScalarMulTest[emulated.Secp256k1, emulated.Secp256k1Scalars]{} +// witness := ScalarMulTest[emulated.Secp256k1, emulated.Secp256k1Scalars]{ +// S: emulated.NewElement[emulated.Secp256k1Scalars](s), +// P: AffinePoint[emulated.Secp256k1]{ +// X: emulated.NewElement[emulated.Secp256k1](secpCurve.Gx), +// Y: emulated.NewElement[emulated.Secp256k1](secpCurve.Gy), +// }, +// Q: AffinePoint[emulated.Secp256k1]{ +// X: emulated.NewElement[emulated.Secp256k1](sx), +// Y: emulated.NewElement[emulated.Secp256k1](sy), +// }, +// } +// err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) +// assert.NoError(err) +// // _, err = frontend.Compile(testCurve.ScalarField(), r1cs.NewBuilder, &circuit) +// // assert.NoError(err) +// } diff --git a/go.mod b/go.mod index 9a9ad62..3f72b0d 100644 --- a/go.mod +++ b/go.mod @@ -1,20 +1,24 @@ -module cubic +module gnark-ed25519 go 1.19 require ( github.com/blang/semver/v4 v4.0.0 // indirect github.com/consensys/bavard v0.1.13 // indirect - github.com/consensys/gnark v0.7.2-0.20220915193524-b33f88c79af6 // indirect + github.com/consensys/gnark v0.7.2-0.20220921094618-a121a3074ee8 // indirect github.com/consensys/gnark-crypto v0.8.1-0.20220819163559-143c75519b0e // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/fxamacker/cbor/v2 v2.2.0 // indirect github.com/google/pprof v0.0.0-20220729232143-a41b82acbcb1 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.16 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rs/zerolog v1.28.0 // indirect + github.com/stretchr/testify v1.8.0 // indirect github.com/x448/float16 v0.8.4 // indirect golang.org/x/exp v0.0.0-20220713135740-79cabaa25d75 // indirect golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect rsc.io/tmplfunc v0.0.3 // indirect ) diff --git a/go.sum b/go.sum index b404acf..3b1c6ca 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/consensys/gnark v0.7.0 h1:zyI8zPAhSazrZPeQpKIFUHLgrnAuxI+EDrFLNizKb9I github.com/consensys/gnark v0.7.0/go.mod h1:oQnMurInsfe+9rG4l8qh8AFVihfuRCS5H3XPJH/6HPM= github.com/consensys/gnark v0.7.2-0.20220915193524-b33f88c79af6 h1:T19XI5vxnMPOdoyyubM81cYr4MHll0n67EDrRjtA2Pg= github.com/consensys/gnark v0.7.2-0.20220915193524-b33f88c79af6/go.mod h1:iN7/IRE6Eu2QKnTJEsoS48suBV0O5XrM+Nzo1ipp6Zw= +github.com/consensys/gnark v0.7.2-0.20220921094618-a121a3074ee8 h1:vVr7kyVKEQGiMtrLsvS37QPOUzdHVT3X1QlXRZHOo2c= +github.com/consensys/gnark v0.7.2-0.20220921094618-a121a3074ee8/go.mod h1:vxk8P9btWUlF9tgqOyB76wXbB6As5IXxkb/4sNJvE0M= github.com/consensys/gnark-crypto v0.7.0 h1:rwdy8+ssmLYRqKp+ryRRgQJl/rCq2uv+n83cOydm5UE= github.com/consensys/gnark-crypto v0.7.0/go.mod h1:KPSuJzyxkJA8xZ/+CV47tyqkr9MmpZA3PXivK4VPrVg= github.com/consensys/gnark-crypto v0.7.1-0.20220603201101-938eff486457 h1:GCxBDfMg0bM1ZN2fi3OfywjDDr19N+SThchczg5kqJQ= @@ -13,6 +15,9 @@ github.com/consensys/gnark-crypto v0.7.1-0.20220603201101-938eff486457/go.mod h1 github.com/consensys/gnark-crypto v0.8.1-0.20220819163559-143c75519b0e h1:FyL5vcbvCIoD20M4Fvy+TXRbXKjT16gq7Uq0QDkyytM= github.com/consensys/gnark-crypto v0.8.1-0.20220819163559-143c75519b0e/go.mod h1:ZTnSzNlt98CpwYIJyk6q/KVcshYWr3fOXXFrrY8a0QQ= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fxamacker/cbor/v2 v2.2.0 h1:6eXqdDDe588rSYAi1HfZKbx6YYQO4mxQ9eC6xYpU/JQ= github.com/fxamacker/cbor/v2 v2.2.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -29,9 +34,16 @@ github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iP github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY= github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= golang.org/x/exp v0.0.0-20220713135740-79cabaa25d75 h1:x03zeu7B2B11ySp+daztnwM5oBJ/8wGUSqrwcw9L0RA= @@ -41,5 +53,9 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI= golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA=