├── .github └── workflows │ └── go.yml ├── LICENSE ├── README.md ├── curve ├── common.go ├── curve_test.go ├── doc.go ├── edwards.go ├── montgomery.go ├── rationalMaps.go ├── selector.go ├── toy │ ├── toy.go │ └── toy_test.go ├── wc.go └── weierstrass.go ├── doc.go ├── field ├── ff.go ├── fp.go ├── fp2.go ├── fp2_test.go ├── fp_test.go └── int.go └── go.mod /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: tozan-ecc 3 | on: [pull_request, push] 4 | jobs: 5 | build: 6 | name: Build Go-${{ matrix.GOVER }} 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | GOVER: ['1.23', '1.22'] 11 | steps: 12 | - name: Checking out 13 | uses: actions/checkout@v4 14 | 15 | - name: Setup Go-${{ matrix.GOVER }} 16 | uses: actions/setup-go@v5 17 | with: 18 | go-version: ${{ matrix.GOVER }} 19 | 20 | - name: Building 21 | run: go build -v . 22 | 23 | - name: Testing 24 | run: go test -v --count=1 ./... 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2020, Armando Faz Hernandez 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tozan-ecc 2 | 3 | ![Go](https://github.com/armfazh/tozan-ecc/workflows/Go/badge.svg) 4 | 5 | Elliptic curve operations in Go. 6 | 7 | ### Features 8 | 9 | Curve models supported: 10 | - Weierstrass 11 | - Montgomery 12 | - Twisted Edwards 13 | 14 | 15 | #### Disclaimer 16 | 17 | This implementation is for reference only. It **MUST NOT** be used in production systems. 18 | 19 | #### License 20 | 21 | [BSD 3-Clause](./LICENSE) 22 | -------------------------------------------------------------------------------- /curve/common.go: -------------------------------------------------------------------------------- 1 | package curve 2 | 3 | import ( 4 | "fmt" 5 | "math/big" 6 | 7 | GF "github.com/armfazh/tozan-ecc/field" 8 | ) 9 | 10 | type params struct { 11 | Name string 12 | F GF.Field 13 | A, B, D GF.Elt 14 | R *big.Int 15 | H *big.Int 16 | } 17 | 18 | func (e *params) String() string { 19 | return fmt.Sprintf("Name: %v\nF: %v\nA: %v\nB: %v\n", e.Name, e.F, e.A, e.B) 20 | } 21 | func (e *params) Field() GF.Field { return e.F } 22 | func (e *params) Order() *big.Int { return e.R } 23 | func (e *params) Cofactor() *big.Int { return e.H } 24 | func (e *params) scalarMult(ec EllCurve, p Point, k *big.Int) Point { 25 | Q := ec.Identity() 26 | for i := k.BitLen() - 1; i >= 0; i-- { 27 | Q = ec.Double(Q) 28 | if k.Bit(i) != 0 { 29 | Q = ec.Add(Q, p) 30 | } 31 | } 32 | return Q 33 | } 34 | 35 | // afPoint is an affine point. 36 | type afPoint struct{ x, y GF.Elt } 37 | 38 | func (p afPoint) String() string { return fmt.Sprintf("(%v, %v)", p.x, p.y) } 39 | func (p *afPoint) X() GF.Elt { return p.x } 40 | func (p *afPoint) Y() GF.Elt { return p.y } 41 | func (p *afPoint) copy() *afPoint { 42 | q := &afPoint{} 43 | q.x = p.x.Copy() 44 | q.y = p.y.Copy() 45 | return q 46 | } 47 | func (p *afPoint) isEqual(f GF.Field, q *afPoint) bool { 48 | return f.AreEqual(p.x, q.x) && f.AreEqual(p.y, q.y) 49 | } 50 | 51 | // infPoint is the point at infinity. 52 | type infPoint struct{} 53 | 54 | func (p infPoint) String() string { return "(inf)" } 55 | func (p *infPoint) X() GF.Elt { return nil } 56 | func (p *infPoint) Y() GF.Elt { return nil } 57 | func (p *infPoint) Copy() Point { return &infPoint{} } 58 | func (p *infPoint) IsEqual(q Point) bool { _, t := q.(*infPoint); return t } 59 | func (p *infPoint) IsIdentity() bool { return true } 60 | func (p *infPoint) IsTwoTorsion() bool { return false } 61 | -------------------------------------------------------------------------------- /curve/curve_test.go: -------------------------------------------------------------------------------- 1 | package curve_test 2 | 3 | import ( 4 | "testing" 5 | 6 | C "github.com/armfazh/tozan-ecc/curve" 7 | "github.com/armfazh/tozan-ecc/curve/toy" 8 | ) 9 | 10 | func TestCurves(t *testing.T) { 11 | for _, curveID := range toy.Curves { 12 | e, g, _ := curveID.New() 13 | order := e.Order().Uint64() 14 | T := make([]C.Point, order) 15 | T[0] = e.Identity() 16 | for i := uint64(1); i < order; i++ { 17 | T[i] = e.Add(T[i-1], g) 18 | if !e.IsOnCurve(T[i]) { 19 | t.Fatalf("point not in the curve: %v\n", T[i]) 20 | } 21 | } 22 | for _, P := range T { 23 | for _, Q := range T { 24 | R := e.Add(P, Q) 25 | if !e.IsOnCurve(R) { 26 | t.Fatalf("point not in the curve: %v\n", R) 27 | } 28 | } 29 | } 30 | } 31 | } 32 | 33 | func BenchmarkCurve(b *testing.B) { 34 | E, P, _ := toy.W0.New() 35 | Q := E.Double(P) 36 | b.Run("double", func(b *testing.B) { 37 | for i := 0; i < b.N; i++ { 38 | P = E.Double(P) 39 | } 40 | }) 41 | b.Run("add", func(b *testing.B) { 42 | for i := 0; i < b.N; i++ { 43 | P = E.Add(P, Q) 44 | } 45 | }) 46 | } 47 | -------------------------------------------------------------------------------- /curve/doc.go: -------------------------------------------------------------------------------- 1 | // Package curve provides definitions of several models of elliptic curves 2 | // defined over finite fields of large prime characteristic. 3 | package curve 4 | 5 | import ( 6 | "math/big" 7 | 8 | GF "github.com/armfazh/tozan-ecc/field" 9 | ) 10 | 11 | // Point represents an elliptic curve point. 12 | type Point interface { 13 | Copy() Point 14 | IsIdentity() bool 15 | IsEqual(Point) bool 16 | IsTwoTorsion() bool 17 | X() GF.Elt 18 | Y() GF.Elt 19 | } 20 | 21 | // EllCurve represents an elliptic curve group. 22 | type EllCurve interface { 23 | Field() GF.Field 24 | Order() *big.Int 25 | Cofactor() *big.Int 26 | NewPoint(x, y GF.Elt) Point 27 | // Predicates 28 | IsOnCurve(Point) bool 29 | IsEqual(EllCurve) bool 30 | IsValid() bool 31 | // Arithmetic operations 32 | Identity() Point 33 | Neg(Point) Point 34 | Add(Point, Point) Point 35 | Double(Point) Point 36 | ClearCofactor(Point) Point 37 | ScalarMult(Point, *big.Int) Point 38 | } 39 | 40 | // RationalMap represents a birational map between two elliptic curves. 41 | type RationalMap interface { 42 | Domain() EllCurve 43 | Codomain() EllCurve 44 | Push(Point) Point 45 | Pull(Point) Point 46 | } 47 | 48 | // Isogeny represents an isogeny between two elliptic curves. 49 | type Isogeny interface { 50 | Domain() EllCurve 51 | Codomain() EllCurve 52 | Push(Point) Point 53 | } 54 | -------------------------------------------------------------------------------- /curve/edwards.go: -------------------------------------------------------------------------------- 1 | package curve 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "math/big" 7 | 8 | GF "github.com/armfazh/tozan-ecc/field" 9 | ) 10 | 11 | // teCurve is a twisted Edwards curve 12 | type teCurve struct{ *params } 13 | 14 | type T = *teCurve 15 | 16 | func (e *teCurve) String() string { 17 | return fmt.Sprintf("Ax^2+y^2=1+Dx^2y^2\nF: %v\nA: %v\nD: %v\n", e.F, e.A, e.D) 18 | } 19 | func (e *teCurve) New() EllCurve { 20 | e.params.D = e.params.B 21 | if e.IsValid() { 22 | return e 23 | } 24 | panic(errors.New("can't instantiate a twisted Edwards curve")) 25 | } 26 | func (e *teCurve) NewPoint(x, y GF.Elt) (P Point) { 27 | if P = (&ptTe{e, &afPoint{x: x, y: y}}); e.IsOnCurve(P) { 28 | return P 29 | } 30 | panic(fmt.Errorf("p:%v not on %v", P, e)) 31 | } 32 | func (e *teCurve) IsValid() bool { 33 | F := e.F 34 | cond1 := !F.AreEqual(e.A, e.D) // A != D 35 | cond2 := !F.IsZero(e.A) // A != 0 36 | cond3 := !F.IsZero(e.D) // D != 0 37 | return cond1 && cond2 && cond3 38 | } 39 | func (e *teCurve) IsEqual(ec EllCurve) bool { 40 | e0 := ec.(*teCurve) 41 | return e.F.IsEqual(e0.F) && e.F.AreEqual(e.A, e0.A) && e.F.AreEqual(e.D, e0.D) 42 | } 43 | func (e *teCurve) IsComplete() bool { 44 | F := e.F 45 | return F.IsSquare(e.A) && !F.IsSquare(e.D) // A != D 46 | } 47 | func (e *teCurve) IsOnCurve(p Point) bool { 48 | P := p.(*ptTe) 49 | F := e.F 50 | var t0, t1, t2 GF.Elt 51 | t0 = F.Sqr(P.x) // x^2 52 | t1 = F.Sqr(P.y) // y^2 53 | t2 = F.Mul(t0, t1) // x^2y^2 54 | t2 = F.Mul(t2, e.D) // Dx^2y^2 55 | t2 = F.Add(t2, F.One()) // 1+Dx^2y^2 56 | t0 = F.Mul(t0, e.A) // Ax^2 57 | t0 = F.Add(t0, t1) // Ax^2+y^2 58 | return F.AreEqual(t0, t2) 59 | } 60 | func (e *teCurve) Identity() Point { return e.NewPoint(e.F.Zero(), e.F.One()) } 61 | func (e *teCurve) Add(p, q Point) Point { 62 | P := p.(*ptTe) 63 | Q := q.(*ptTe) 64 | F := e.F 65 | 66 | var t0, t1, t2, t3 GF.Elt 67 | t0 = F.Mul(e.D, P.x) // Dx1 68 | t0 = F.Mul(t0, P.y) // Dx1y1 69 | t0 = F.Mul(t0, Q.x) // Dx1y1x2 70 | t0 = F.Mul(t0, Q.y) // Dx1y1x2y2 71 | t2 = F.Add(F.One(), t0) // 1+Dx1y1x2y2 72 | t3 = F.Sub(F.One(), t0) // 1-Dx1y1x2y2 73 | t2 = F.Inv(t2) // 1/(1+Dx1y1x2y2) 74 | t3 = F.Inv(t3) // 1/(1-Dx1y1x2y2) 75 | 76 | t0 = F.Mul(P.x, Q.y) // x1y2 77 | t1 = F.Mul(Q.x, P.y) // x2y1 78 | t0 = F.Add(t0, t1) // x1y2+x2y1 79 | x := F.Mul(t0, t2) // (x1y2+x2y1)/(1+Dx1y1x2y2) 80 | 81 | t0 = F.Mul(P.y, Q.y) // y1y2 82 | t1 = F.Mul(P.x, Q.x) // x1x2 83 | t1 = F.Mul(t1, e.A) // Ax1x2 84 | t0 = F.Sub(t0, t1) // y1y2-Ax1x2 85 | y := F.Mul(t0, t3) // (y1y2-Ax1x2)/(1-Dx1y1x2y2) 86 | 87 | return &ptTe{e, &afPoint{x: x, y: y}} 88 | } 89 | func (e *teCurve) Neg(p Point) Point { 90 | P := p.(*ptTe) 91 | return &ptTe{e, &afPoint{x: e.F.Neg(P.x), y: P.y.Copy()}} 92 | } 93 | func (e *teCurve) Double(p Point) Point { return e.Add(p, p) } 94 | func (e *teCurve) ScalarMult(p Point, k *big.Int) Point { return e.params.scalarMult(e, p, k) } 95 | 96 | func (e *teCurve) ClearCofactor(p Point) Point { return e.ScalarMult(p, e.H) } 97 | 98 | type ptTe struct { 99 | *teCurve 100 | *afPoint 101 | } 102 | 103 | func (p *ptTe) String() string { return p.afPoint.String() } 104 | func (p *ptTe) Copy() Point { return &ptTe{p.teCurve, p.copy()} } 105 | func (p *ptTe) IsEqual(q Point) bool { 106 | qq := q.(*ptTe) 107 | return p.teCurve.IsEqual(qq.teCurve) && p.isEqual(p.F, qq.afPoint) 108 | } 109 | func (p *ptTe) IsIdentity() bool { return p.F.IsZero(p.x) && p.F.AreEqual(p.y, p.F.One()) } 110 | func (p *ptTe) IsTwoTorsion() bool { return p.F.IsZero(p.x) && p.F.AreEqual(p.y, p.F.Elt(-1)) } 111 | -------------------------------------------------------------------------------- /curve/montgomery.go: -------------------------------------------------------------------------------- 1 | package curve 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "math/big" 7 | 8 | GF "github.com/armfazh/tozan-ecc/field" 9 | ) 10 | 11 | // mtCurve is a Montgomery curve 12 | type mtCurve struct{ *params } 13 | 14 | type M = *mtCurve 15 | 16 | func (e *mtCurve) String() string { return "By^2=x^3+Ax^2+x\n" + e.params.String() } 17 | func (e *mtCurve) New() EllCurve { 18 | if e.IsValid() { 19 | return e 20 | } 21 | panic(errors.New("can't instantiate a Montgomery curve")) 22 | } 23 | 24 | func (e *mtCurve) NewPoint(x, y GF.Elt) (P Point) { 25 | if P = (&ptMt{e, &afPoint{x: x, y: y}}); e.IsOnCurve(P) { 26 | return P 27 | } 28 | panic(fmt.Errorf("p:%v not on %v", P, e)) 29 | } 30 | func (e *mtCurve) IsValid() bool { 31 | F := e.F 32 | t0 := F.Sqr(e.A) // A^2 33 | t0 = F.Sub(t0, F.Elt(4)) // A^2-4 34 | t0 = F.Mul(t0, e.B) // B(A^2-4) 35 | return !F.IsZero(t0) // B(A^2-4) != 0 36 | } 37 | func (e *mtCurve) IsEqual(ec EllCurve) bool { 38 | e0 := ec.(*mtCurve) 39 | return e.F.IsEqual(e0.F) && e.F.AreEqual(e.A, e0.A) && e.F.AreEqual(e.B, e0.B) 40 | } 41 | func (e *mtCurve) IsOnCurve(p Point) bool { 42 | if _, isZero := p.(*infPoint); isZero { 43 | return isZero 44 | } 45 | P := p.(*ptMt) 46 | F := e.F 47 | var t0, t1 GF.Elt 48 | t0 = F.Add(P.x, e.A) // x+A 49 | t0 = F.Mul(t0, P.x) // (x+A)x 50 | t0 = F.Add(t0, F.One()) // (x+A)x+1 51 | t0 = F.Mul(t0, P.x) // ((x+A)x+1)x 52 | t1 = F.Sqr(P.y) // y^2 53 | t1 = F.Mul(t1, e.B) // By^2 54 | return F.AreEqual(t0, t1) 55 | } 56 | func (e *mtCurve) Identity() Point { return &infPoint{} } 57 | func (e *mtCurve) Add(p, q Point) Point { 58 | if p.IsIdentity() { 59 | return q.Copy() 60 | } else if q.IsIdentity() { 61 | return p.Copy() 62 | } else if p.IsEqual(e.Neg(q)) { 63 | return e.Identity() 64 | } else if p.IsEqual(q) { 65 | return e.Double(p) 66 | } else { 67 | return e.add(p, q) 68 | } 69 | } 70 | func (e *mtCurve) Neg(p Point) Point { 71 | if _, isZero := p.(*infPoint); isZero { 72 | return e.Identity() 73 | } 74 | P := p.(*ptMt) 75 | return &ptMt{e, &afPoint{x: P.x.Copy(), y: e.F.Neg(P.y)}} 76 | } 77 | func (e *mtCurve) add(p, q Point) Point { 78 | P := p.(*ptMt) 79 | Q := q.(*ptMt) 80 | F := e.F 81 | 82 | if F.AreEqual(P.x, Q.x) { 83 | panic("wrong inputs") 84 | } 85 | 86 | var t0, t1, ll GF.Elt 87 | t0 = F.Sub(Q.y, P.y) // (y2-y1) 88 | t1 = F.Sub(Q.x, P.x) // (x2-x1) 89 | t1 = F.Inv(t1) // 1/(x2-x1) 90 | ll = F.Mul(t0, t1) // l = (y2-y1)/(x2-x1) 91 | 92 | t0 = F.Sqr(ll) // l^2 93 | t0 = F.Mul(t0, e.B) // Bl^2 94 | t0 = F.Sub(t0, e.A) // Bl^2-A 95 | t0 = F.Sub(t0, P.x) // Bl^2-A-x1 96 | x := F.Sub(t0, Q.x) // x' = Bl^2-A-x1-x2 97 | 98 | t0 = F.Sub(P.x, x) // x1-x3 99 | t0 = F.Mul(t0, ll) // l(x1-x3) 100 | y := F.Sub(t0, P.y) // y3 = l(x1-x3)-y1 101 | 102 | return &ptMt{e, &afPoint{x: x, y: y}} 103 | } 104 | func (e *mtCurve) Double(p Point) Point { 105 | if _, ok := p.(*infPoint); ok { 106 | return e.Identity() 107 | } 108 | P := p.(*ptMt) 109 | if P.IsTwoTorsion() { 110 | return e.Identity() 111 | } 112 | 113 | F := e.F 114 | var t0, t1, ll GF.Elt 115 | t0 = F.Mul(F.Elt(3), P.x) // 3x 116 | t1 = F.Mul(F.Elt(2), e.A) // 2A 117 | t0 = F.Add(t0, t1) // 3x+2A 118 | t0 = F.Mul(t0, P.x) // (3x+2A)x 119 | t1 = F.Add(t0, F.One()) // (3x+2A)x+1 120 | t0 = F.Mul(F.Elt(2), e.B) // 2B 121 | t0 = F.Mul(t0, P.y) // 2By 122 | t0 = F.Inv(t0) // 1/2By 123 | ll = F.Mul(t1, t0) // l = (3x^2+2Ax+1)/(2By) 124 | 125 | t0 = F.Sqr(ll) // l^2 126 | t0 = F.Mul(t0, e.B) // Bl^2 127 | t0 = F.Sub(t0, e.A) // Bl^2-A 128 | t0 = F.Sub(t0, P.x) // Bl^2-A-x 129 | x := F.Sub(t0, P.x) // x' = Bl^2-A-2x 130 | 131 | t0 = F.Sub(P.x, x) // x-x' 132 | t0 = F.Mul(t0, ll) // l(x-x') 133 | y := F.Sub(t0, P.y) // y3 = l(x-x')-y1 134 | 135 | return &ptMt{e, &afPoint{x: x, y: y}} 136 | } 137 | 138 | func (e *mtCurve) ClearCofactor(p Point) Point { return e.ScalarMult(p, e.H) } 139 | func (e *mtCurve) ScalarMult(p Point, k *big.Int) Point { return e.params.scalarMult(e, p, k) } 140 | 141 | // ptMt is an affine point on a Montgomery curve. 142 | type ptMt struct { 143 | *mtCurve 144 | *afPoint 145 | } 146 | 147 | func (p *ptMt) String() string { return p.afPoint.String() } 148 | func (p *ptMt) Copy() Point { return &ptMt{p.mtCurve, p.copy()} } 149 | func (p *ptMt) IsEqual(q Point) bool { 150 | qq := q.(*ptMt) 151 | return p.mtCurve.IsEqual(qq.mtCurve) && p.isEqual(p.F, qq.afPoint) 152 | } 153 | func (p *ptMt) IsIdentity() bool { return false } 154 | func (p *ptMt) IsTwoTorsion() bool { return p.F.IsZero(p.y) } 155 | -------------------------------------------------------------------------------- /curve/rationalMaps.go: -------------------------------------------------------------------------------- 1 | package curve 2 | 3 | import GF "github.com/armfazh/tozan-ecc/field" 4 | 5 | type mt2wec struct { 6 | E0 *mtCurve 7 | E1 *wcCurve 8 | invB GF.Elt 9 | } 10 | 11 | func (e *mtCurve) ToWeierstrassC() RationalMap { 12 | F := e.Field() 13 | invB := F.Inv(e.params.B) 14 | a := F.Mul(invB, e.params.A) 15 | b := F.Sqr(invB) 16 | e1 := WeierstrassC.New("WC from "+e.Name, F, a, b, e.params.R, e.params.H) 17 | return &mt2wec{E0: e, E1: e1.(*wcCurve), invB: invB} 18 | } 19 | 20 | func (r *mt2wec) Domain() EllCurve { return r.E0 } 21 | func (r *mt2wec) Codomain() EllCurve { return r.E1 } 22 | func (r *mt2wec) Push(p Point) Point { 23 | if p.IsIdentity() { 24 | return r.E1.Identity() 25 | } 26 | F := r.E0.Field() 27 | 28 | P := p.(*ptMt) 29 | x := F.Mul(P.x, r.invB) // s = x/B 30 | y := F.Mul(P.y, r.invB) // t = y/B 31 | return r.E1.NewPoint(x, y) 32 | } 33 | func (r *mt2wec) Pull(p Point) Point { 34 | if p.IsIdentity() { 35 | return r.E0.Identity() 36 | } 37 | F := r.E0.Field() 38 | P := p.(*ptWc) 39 | x := F.Mul(P.x, r.E0.B) // x = s*B 40 | y := F.Mul(P.y, r.E0.B) // y = t*B 41 | return r.E0.NewPoint(x, y) 42 | } 43 | 44 | type te2wec struct { 45 | E0 *teCurve 46 | E1 *wcCurve 47 | invSqrtD GF.Elt // 4/(a-d) 48 | } 49 | 50 | func (e *teCurve) ToWeierstrassC() RationalMap { 51 | F := e.Field() 52 | half := F.Inv(F.Elt(2)) // 1/2 53 | t0 := F.Add(e.params.A, e.params.D) // a+d 54 | a := F.Mul(t0, half) // A = (a+d)/2 55 | 56 | t0 = F.Sub(e.params.A, e.params.D) // a-d 57 | t0 = F.Mul(t0, half) // (a-d)/2 58 | t0 = F.Mul(t0, half) // (a-d)/4 59 | invSqrtD := F.Inv(t0) // 4/(a-d) 60 | b := F.Sqr(t0) // B = (a-d)^2/16 61 | e1 := WeierstrassC.New("WC from "+e.Name, F, a, b, e.params.R, e.params.H) 62 | return &te2wec{E0: e, E1: e1.(*wcCurve), invSqrtD: invSqrtD} 63 | } 64 | 65 | func (r *te2wec) Domain() EllCurve { return r.E0 } 66 | func (r *te2wec) Codomain() EllCurve { return r.E1 } 67 | func (r *te2wec) Push(p Point) Point { 68 | if p.IsIdentity() { 69 | return r.E1.Identity() 70 | } 71 | F := r.E0.Field() 72 | P := p.(*ptTe) 73 | t0 := F.Add(F.One(), P.y) // 1+y 74 | t1 := F.Sub(F.One(), P.y) // 1-y 75 | t1 = F.Mul(t1, r.invSqrtD) // invSqrtD*(1-y) 76 | t1 = F.Inv(t1) // 1/(invSqrtD*(1-y)) 77 | x := F.Mul(t0, t1) // x = (1+y)/(invSqrtD*(1-y)) 78 | t0 = F.Inv(P.y) // 1/y 79 | y := F.Mul(x, t0) // y = x/y 80 | return r.E1.NewPoint(x, y) 81 | } 82 | func (r *te2wec) Pull(p Point) Point { 83 | if p.IsIdentity() { 84 | return r.E0.Identity() 85 | } 86 | P := p.(*ptWc) 87 | F := r.E0.Field() 88 | if P.IsTwoTorsion() { 89 | return r.E0.NewPoint(F.Zero(), F.Elt(-1)) 90 | } 91 | t0 := F.Inv(P.y) // 1/y 92 | x := F.Mul(P.x, t0) // X = x/y 93 | t0 = F.Mul(r.invSqrtD, P.x) // invSqrtD*x 94 | t1 := F.Add(t0, F.One()) // invSqrtD*x+1 95 | t2 := F.Sub(t0, F.One()) // invSqrtD*x-1 96 | t1 = F.Inv(t1) // 1/(invSqrtD*x+1) 97 | y := F.Mul(t1, t2) // Y = (invSqrtD*x-1)/(invSqrtD*x+1) 98 | return r.E0.NewPoint(x, y) 99 | } 100 | 101 | type wc2we struct { 102 | E0 *wcCurve 103 | E1 *weCurve 104 | Adiv3 GF.Elt 105 | } 106 | 107 | func (e *wcCurve) ToWeierstrass() RationalMap { 108 | F := e.Field() 109 | var t0, t1 GF.Elt 110 | t0 = F.Inv(F.Elt(3)) // 1/3 111 | Adiv3 := F.Mul(t0, e.A) // A/3 112 | t0 = F.Neg(Adiv3) // -A/3 113 | t0 = F.Mul(t0, e.A) // -A^2/3 114 | A := F.Add(t0, e.B) // -A^2/3 + B 115 | 116 | t0 = F.Mul(F.Elt(9), e.B) // 9B 117 | t1 = F.Sqr(e.A) // A^2 118 | t1 = F.Add(t1, t1) // 2A^2 119 | t1 = F.Sub(t1, t0) // 2A^2 - 9B 120 | t1 = F.Mul(t1, e.A) // A(2A^2 - 9B) 121 | t0 = F.Inv(F.Elt(27)) // 1/27 122 | B := F.Mul(t0, t1) // A(2A^2 - 9B)/27 123 | e1 := Weierstrass.New("W from "+e.Name, F, A, B, e.params.R, e.params.H) 124 | return &wc2we{E0: e, E1: e1.(*weCurve), Adiv3: Adiv3} 125 | } 126 | func (r *wc2we) Domain() EllCurve { return r.E0 } 127 | func (r *wc2we) Codomain() EllCurve { return r.E1 } 128 | func (r *wc2we) Push(p Point) Point { 129 | if p.IsIdentity() { 130 | return r.E1.Identity() 131 | } 132 | P := p.(*ptWc) 133 | F := r.E0.Field() 134 | xx := F.Add(P.x, r.Adiv3) 135 | return r.E1.NewPoint(xx, P.y) 136 | } 137 | func (r *wc2we) Pull(p Point) Point { 138 | if p.IsIdentity() { 139 | return r.E0.Identity() 140 | } 141 | P := p.(*ptWe) 142 | F := r.E0.Field() 143 | xx := F.Sub(P.x, r.Adiv3) 144 | return r.E0.NewPoint(xx, P.y) 145 | } 146 | -------------------------------------------------------------------------------- /curve/selector.go: -------------------------------------------------------------------------------- 1 | package curve 2 | 3 | import ( 4 | "math/big" 5 | 6 | GF "github.com/armfazh/tozan-ecc/field" 7 | ) 8 | 9 | type Model int 10 | 11 | const ( 12 | Weierstrass Model = iota 13 | WeierstrassC 14 | TwistedEdwards 15 | Montgomery 16 | ) 17 | 18 | func (m Model) New(name string, f GF.Field, a, b GF.Elt, r, h *big.Int) EllCurve { 19 | p := ¶ms{Name: name, F: f, A: a, B: b, R: r, H: h} 20 | switch m { 21 | case Weierstrass: 22 | return (&weCurve{p}).New() 23 | case WeierstrassC: 24 | return (&wcCurve{params: p}).New() 25 | case TwistedEdwards: 26 | return (&teCurve{p}).New() 27 | case Montgomery: 28 | return (&mtCurve{p}).New() 29 | default: 30 | panic("elliptic curve model not supported") 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /curve/toy/toy.go: -------------------------------------------------------------------------------- 1 | // Package toy provides small instances of elliptic curves. 2 | package toy 3 | 4 | import ( 5 | "fmt" 6 | "math/big" 7 | 8 | C "github.com/armfazh/tozan-ecc/curve" 9 | GF "github.com/armfazh/tozan-ecc/field" 10 | ) 11 | 12 | // ID is an identifier of a toy curve. 13 | type ID string 14 | 15 | const ( 16 | W0 ID = "W0" 17 | W1 ID = "W1" 18 | W1ISO ID = "W1ISO" 19 | W2 ID = "W2" 20 | W3 ID = "W3" 21 | W4 ID = "W4" 22 | WC0 ID = "WC0" 23 | M0 ID = "M0" 24 | M1 ID = "M1" 25 | E0 ID = "E0" 26 | E1 ID = "E1" 27 | ) 28 | 29 | type params struct { 30 | model C.Model 31 | p, m int 32 | a, b int 33 | h, r int 34 | x, y interface{} 35 | } 36 | 37 | // Curves is a list of toy curves. 38 | var Curves []ID 39 | var toyCurves map[ID]*params 40 | 41 | func init() { 42 | Curves = make([]ID, 0, 10) 43 | toyCurves = make(map[ID]*params) 44 | 45 | W0.register(¶ms{model: C.Weierstrass, p: 53, m: 1, a: 3, b: 2, r: 51, h: 3, x: 46, y: 3}) 46 | W1.register(¶ms{model: C.Weierstrass, p: 53, m: 1, a: 0, b: 1, r: 54, h: 2, x: 13, y: 5}) 47 | W1ISO.register(¶ms{model: C.Weierstrass, p: 53, m: 1, a: 38, b: 22, r: 54, h: 2, x: 41, y: 45}) 48 | W2.register(¶ms{model: C.Weierstrass, p: 53, m: 1, a: 0, b: 2, r: 51, h: 3, x: 37, y: 27}) 49 | W3.register(¶ms{model: C.Weierstrass, p: 59, m: 1, a: 16, b: 0, r: 60, h: 4, x: 33, y: 11}) 50 | WC0.register(¶ms{model: C.WeierstrassC, p: 53, m: 1, a: 2, b: 3, r: 66, h: 6, x: 45, y: 4}) 51 | M0.register(¶ms{model: C.Montgomery, p: 53, m: 1, a: 4, b: 3, r: 44, h: 4, x: 16, y: 4}) 52 | M1.register(¶ms{model: C.Montgomery, p: 53, m: 1, a: 3, b: 1, r: 48, h: 4, x: 14, y: 22}) 53 | E0.register(¶ms{model: C.TwistedEdwards, p: 53, m: 1, a: 1, b: 3, r: 44, h: 4, x: 17, y: 49}) 54 | E1.register(¶ms{model: C.TwistedEdwards, p: 53, m: 1, a: -1, b: 12, r: 48, h: 4, x: 3, y: 19}) 55 | W4.register(¶ms{model: C.Weierstrass, p: 19, m: 2, a: 1, b: 4, r: 399, h: 3, x: []interface{}{0, 1}, y: 17}) 56 | } 57 | 58 | func (id ID) register(p *params) { toyCurves[id] = p; Curves = append(Curves, id) } 59 | 60 | // New returns an elliptic curve and a generator point. 61 | func (id ID) New() (C.EllCurve, C.Point, error) { 62 | if v, ok := toyCurves[id]; ok { 63 | var F GF.Field 64 | if v.m == 1 { 65 | F = GF.NewFp(fmt.Sprintf("%v", v.p), v.p) 66 | } else if v.m == 2 { 67 | F = GF.NewFp2(fmt.Sprintf("%v", v.p), v.p) 68 | } 69 | E := v.model.New(string(id), F, 70 | F.Elt(v.a), F.Elt(v.b), 71 | big.NewInt(int64(v.r)), big.NewInt(int64(v.h))) 72 | P := E.NewPoint(F.Elt(v.x), F.Elt(v.y)) 73 | return E, P, nil 74 | } 75 | return nil, nil, fmt.Errorf("curve not supported") 76 | } 77 | -------------------------------------------------------------------------------- /curve/toy/toy_test.go: -------------------------------------------------------------------------------- 1 | package toy_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/armfazh/tozan-ecc/curve/toy" 7 | ) 8 | 9 | func TestGenerate(t *testing.T) { 10 | for _, curveId := range toy.Curves { 11 | if _, _, err := curveId.New(); err != nil { 12 | t.Fatalf("Curve: %v %v", curveId, err) 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /curve/wc.go: -------------------------------------------------------------------------------- 1 | package curve 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "math/big" 7 | 8 | GF "github.com/armfazh/tozan-ecc/field" 9 | ) 10 | 11 | // wcCurve is a Weierstrass curve 12 | type wcCurve struct { 13 | *params 14 | RationalMap 15 | } 16 | 17 | type WC = *wcCurve 18 | 19 | func (e *wcCurve) String() string { return "y^2=x^3+Ax^2+Bx\n" + e.params.String() } 20 | func (e *wcCurve) New() EllCurve { 21 | if e.IsValid() { 22 | e.RationalMap = e.ToWeierstrass() 23 | return e 24 | } 25 | panic(errors.New("can't instantiate a WeierstrassC curve")) 26 | } 27 | func (e *wcCurve) NewPoint(x, y GF.Elt) (P Point) { 28 | if P = (&ptWc{e, &afPoint{x: x, y: y}}); e.IsOnCurve(P) { 29 | return P 30 | } 31 | panic(fmt.Errorf("%v not on %v", P, e)) 32 | } 33 | 34 | func (e *wcCurve) IsValid() bool { 35 | F := e.F 36 | t0 := F.Sqr(e.A) // A^2 37 | t1 := F.Add(e.B, e.B) // 2B 38 | t1 = F.Add(t1, t1) // 4B 39 | t0 = F.Sub(t0, t1) // A^2-4B 40 | t0 = F.Mul(t0, e.B) // B(A^2-4B) 41 | return !F.IsZero(t0) // B(A^2-4B) != 0 42 | } 43 | func (e *wcCurve) IsEqual(ec EllCurve) bool { 44 | e0 := ec.(*weCurve) 45 | return e.F.IsEqual(e0.F) && e.F.AreEqual(e.A, e0.A) && e.F.AreEqual(e.B, e0.B) 46 | } 47 | func (e *wcCurve) Identity() Point { return &infPoint{} } 48 | func (e *wcCurve) IsOnCurve(p Point) bool { return e.Codomain().IsOnCurve(e.Push(p)) } 49 | func (e *wcCurve) Add(p, q Point) Point { return e.Pull(e.Codomain().Add(e.Push(p), e.Push(q))) } 50 | func (e *wcCurve) Double(p Point) Point { return e.Pull(e.Codomain().Double(e.Push(p))) } 51 | func (e *wcCurve) Neg(p Point) Point { return e.Pull(e.Codomain().Neg(e.Push(p))) } 52 | func (e *wcCurve) ClearCofactor(p Point) Point { return e.Pull(e.Codomain().ClearCofactor(e.Push(p))) } 53 | func (e *wcCurve) ScalarMult(p Point, k *big.Int) Point { return e.params.scalarMult(e, p, k) } 54 | 55 | // ptWc is an affine point on a wcCurve curve. 56 | type ptWc struct { 57 | *wcCurve 58 | *afPoint 59 | } 60 | 61 | func (p *ptWc) String() string { return p.afPoint.String() } 62 | func (p *ptWc) Copy() Point { return &ptWc{p.wcCurve, p.copy()} } 63 | func (p *ptWc) IsEqual(q Point) bool { 64 | qq := q.(*ptWc) 65 | return p.wcCurve.IsEqual(qq.wcCurve) && p.isEqual(p.F, qq.afPoint) 66 | } 67 | func (p *ptWc) IsIdentity() bool { return false } 68 | func (p *ptWc) IsTwoTorsion() bool { return p.F.IsZero(p.y) } 69 | -------------------------------------------------------------------------------- /curve/weierstrass.go: -------------------------------------------------------------------------------- 1 | package curve 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "math/big" 7 | 8 | GF "github.com/armfazh/tozan-ecc/field" 9 | ) 10 | 11 | // weCurve is a Weierstrass curve 12 | type weCurve struct{ *params } 13 | 14 | type W = *weCurve 15 | 16 | func (e *weCurve) String() string { return "y^2=x^3+Ax+B\n" + e.params.String() } 17 | func (e *weCurve) New() EllCurve { 18 | if e.IsValid() { 19 | return e 20 | } 21 | panic(errors.New("can't instantiate a Weierstrass curve")) 22 | } 23 | 24 | // NewPoint generates 25 | func (e *weCurve) NewPoint(x, y GF.Elt) (P Point) { 26 | if P = (&ptWe{e, &afPoint{x: x, y: y}}); e.IsOnCurve(P) { 27 | return P 28 | } 29 | panic(fmt.Errorf("p=%v not on curve", P)) 30 | } 31 | 32 | func (e *weCurve) IsValid() bool { 33 | F := e.F 34 | t0 := F.Sqr(e.A) // A^2 35 | t0 = F.Mul(t0, e.A) // A^3 36 | t0 = F.Add(t0, t0) // 2A^3 37 | t0 = F.Add(t0, t0) // 4A^3 38 | t1 := F.Sqr(e.B) // B^3 39 | t1 = F.Mul(t1, F.Elt(27)) // 27B^2 40 | t0 = F.Add(t0, t1) // 4A^3+27B^2 41 | t0 = F.Add(t0, t0) // 2(4A^3+27B^2) 42 | t0 = F.Add(t0, t0) // 4(4A^3+27B^2) 43 | t0 = F.Add(t0, t0) // 8(4A^3+27B^2) 44 | t0 = F.Add(t0, t0) // 16(4A^3+27B^2) 45 | t0 = F.Neg(t0) // -16(4A^3+27B^2) 46 | return !F.IsZero(t0) // -16(4A^3+27B^2) != 0 47 | } 48 | func (e *weCurve) IsEqual(ec EllCurve) bool { 49 | e0 := ec.(*weCurve) 50 | return e.F.IsEqual(e0.F) && e.F.AreEqual(e.A, e0.A) && e.F.AreEqual(e.B, e0.B) 51 | } 52 | func (e *weCurve) IsOnCurve(p Point) bool { 53 | if _, isZero := p.(*infPoint); isZero { 54 | return isZero 55 | } 56 | P := p.(*ptWe) 57 | F := e.F 58 | t0 := e.EvalRHS(P.x) 59 | t1 := F.Sqr(P.y) // y^2 60 | return F.AreEqual(t0, t1) 61 | } 62 | func (e *weCurve) EvalRHS(x GF.Elt) GF.Elt { 63 | F := e.F 64 | t0 := F.Sqr(x) // x^2 65 | t0 = F.Add(t0, e.A) // x^2+A 66 | t0 = F.Mul(t0, x) // (x^2+A)x 67 | return F.Add(t0, e.B) // (x^2+A)x+B 68 | } 69 | func (e *weCurve) Identity() Point { return &infPoint{} } 70 | func (e *weCurve) Add(p, q Point) Point { 71 | if p.IsIdentity() { 72 | return q.Copy() 73 | } else if q.IsIdentity() { 74 | return p.Copy() 75 | } else if p.IsEqual(e.Neg(q)) { 76 | return e.Identity() 77 | } else if p.IsEqual(q) { 78 | return e.Double(p) 79 | } else { 80 | return e.add(p, q) 81 | } 82 | } 83 | func (e *weCurve) Neg(p Point) Point { 84 | if _, isZero := p.(*infPoint); isZero { 85 | return e.Identity() 86 | } 87 | P := p.(*ptWe) 88 | return &ptWe{e, &afPoint{x: P.x.Copy(), y: e.F.Neg(P.y)}} 89 | } 90 | func (e *weCurve) add(p, q Point) Point { 91 | P := p.(*ptWe) 92 | Q := q.(*ptWe) 93 | F := e.F 94 | 95 | if F.AreEqual(P.x, Q.x) { 96 | panic("wrong inputs") 97 | } 98 | 99 | var t0, t1, ll GF.Elt 100 | t0 = F.Sub(Q.y, P.y) // (y2-y1) 101 | t1 = F.Sub(Q.x, P.x) // (x2-x1) 102 | t1 = F.Inv(t1) // 1/(x2-x1) 103 | ll = F.Mul(t0, t1) // l = (y2-y1)/(x2-x1) 104 | 105 | t0 = F.Sqr(ll) // l^2 106 | t0 = F.Sub(t0, P.x) // l^2-x1 107 | x := F.Sub(t0, Q.x) // x' = l^2-x1-x2 108 | 109 | t0 = F.Sub(P.x, x) // x1-x3 110 | t0 = F.Mul(t0, ll) // l(x1-x3) 111 | y := F.Sub(t0, P.y) // y3 = l(x1-x3)-y1 112 | 113 | return &ptWe{e, &afPoint{x: x, y: y}} 114 | } 115 | func (e *weCurve) Double(p Point) Point { 116 | if _, ok := p.(*infPoint); ok { 117 | return e.Identity() 118 | } 119 | P := p.(*ptWe) 120 | if P.IsTwoTorsion() { 121 | return e.Identity() 122 | } 123 | 124 | F := e.F 125 | var t0, t1, ll GF.Elt 126 | t0 = F.Sqr(P.x) // x^2 127 | t0 = F.Mul(t0, F.Elt(3)) // 3x^2 128 | t0 = F.Add(t0, e.A) // 3x^2+A 129 | t1 = F.Add(P.y, P.y) // 2y 130 | t1 = F.Inv(t1) // 1/2y 131 | ll = F.Mul(t0, t1) // l = (3x^2+2A)/(2y) 132 | 133 | t0 = F.Sqr(ll) // l^2 134 | t0 = F.Sub(t0, P.x) // l^2-x 135 | x := F.Sub(t0, P.x) // x' = l^2-2x 136 | 137 | t0 = F.Sub(P.x, x) // x-x' 138 | t0 = F.Mul(t0, ll) // l(x-x') 139 | y := F.Sub(t0, P.y) // y3 = l(x-x')-y1 140 | 141 | return &ptWe{e, &afPoint{x: x, y: y}} 142 | } 143 | func (e *weCurve) ClearCofactor(p Point) Point { return e.ScalarMult(p, e.H) } 144 | func (e *weCurve) ScalarMult(p Point, k *big.Int) Point { return e.params.scalarMult(e, p, k) } 145 | 146 | // ptWe is an affine point on a weCurve curve. 147 | type ptWe struct { 148 | *weCurve 149 | *afPoint 150 | } 151 | 152 | func (p *ptWe) String() string { return p.afPoint.String() } 153 | func (p *ptWe) Copy() Point { return &ptWe{p.weCurve, p.copy()} } 154 | func (p *ptWe) IsEqual(q Point) bool { 155 | qq := q.(*ptWe) 156 | return p.weCurve.IsEqual(qq.weCurve) && p.isEqual(p.F, qq.afPoint) 157 | } 158 | func (p *ptWe) IsIdentity() bool { return false } 159 | func (p *ptWe) IsTwoTorsion() bool { return p.F.IsZero(p.y) } 160 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // Package ecc provides mathematical operations over elliptic curves. 2 | package ecc 3 | -------------------------------------------------------------------------------- /field/ff.go: -------------------------------------------------------------------------------- 1 | // Package field provides implementations of finite fields of large-prime characteristic. 2 | package field 3 | 4 | import ( 5 | "io" 6 | "math/big" 7 | ) 8 | 9 | // Elt represents a finite field element. 10 | type Elt interface { 11 | Copy() Elt // Makes a copy of the element. 12 | Polynomial() []*big.Int // Returns a polynomial representation of the element. 13 | } 14 | 15 | // Field describes the operations required to implement a finite field. 16 | type Field interface { 17 | // Constructing elements 18 | Zero() Elt // Returns the Zero element. 19 | One() Elt // Returns the One element. 20 | Elt(interface{}) Elt // Constructor of elements from an int, uint, or string. 21 | Rand(r io.Reader) Elt // Returns an elements chosen at random. 22 | Generator() Elt // Returns an additive generator. 23 | // Properties 24 | P() *big.Int // Characteristic of the field. 25 | Order() *big.Int // Size of the field. 26 | Ext() uint // Extension degree of field. 27 | BitLen() int // Bit length of modulus. 28 | // Predicates 29 | AreEqual(Elt, Elt) bool // Returns true if both elements are equivalent. 30 | IsZero(Elt) bool // Returns true if the element is equivalent to zero. 31 | IsSquare(Elt) bool // Returns true if the element is a quadratic residue. 32 | IsEqual(Field) bool // Returns true if the input field is equal to the receiver. 33 | // Arithmetic operations 34 | Neg(x Elt) Elt // Returns -x. 35 | Add(x, y Elt) Elt // Returns x+y. 36 | Sub(x, y Elt) Elt // Returns x-y. 37 | Mul(x, y Elt) Elt // Returns x*y. 38 | Sqr(x Elt) Elt // Returns x^2. 39 | Inv(x Elt) Elt // Returns 1/x. 40 | Exp(x Elt, n *big.Int) Elt // Returns x^n. 41 | Inv0(Elt) Elt // Returns 1/x, and 0 if x=0. 42 | CMov(x, y Elt, b bool) Elt // Returns x if b=false, otherwise, returns y. 43 | Sgn0(x Elt) int // Returns the sign of x. 44 | hasSqrt // Returns a square-root of x. 45 | } 46 | 47 | type hasSqrt interface{ Sqrt(Elt) Elt } 48 | -------------------------------------------------------------------------------- /field/fp.go: -------------------------------------------------------------------------------- 1 | package field 2 | 3 | import ( 4 | "crypto/rand" 5 | "fmt" 6 | "io" 7 | "math/big" 8 | ) 9 | 10 | // fpElt is a prime field element. 11 | type fpElt struct{ n *big.Int } 12 | 13 | func (e fpElt) String() string { return "0x" + e.n.Text(16) } 14 | func (e fpElt) Copy() Elt { return &fpElt{new(big.Int).Set(e.n)} } 15 | func (e fpElt) Polynomial() []*big.Int { return []*big.Int{new(big.Int).Set(e.n)} } 16 | 17 | // fp implements a prime field. 18 | type fp struct { 19 | p *big.Int 20 | name string 21 | cte struct { 22 | pMinus1div2 *big.Int 23 | pMinus2 *big.Int 24 | } 25 | hasSqrt 26 | } 27 | 28 | // NewFp creates a prime field as Z/pZ given p as an int, uint, *big.Int or string. 29 | func NewFp(name string, p interface{}) Field { 30 | prime := FromType(p) 31 | if !prime.ProbablyPrime(4) { 32 | panic(fmt.Errorf("Modulus is not prime p:%v", prime)) 33 | } 34 | f := fp{p: prime, name: name} 35 | f.precmp() 36 | return f 37 | } 38 | 39 | func (f *fp) precmp() { 40 | pMinus1div2 := big.NewInt(1) 41 | pMinus1div2.Sub(f.p, pMinus1div2) 42 | pMinus1div2.Rsh(pMinus1div2, 1) 43 | 44 | pMinus2 := big.NewInt(2) 45 | pMinus2.Sub(f.p, pMinus2) 46 | f.cte.pMinus1div2 = pMinus1div2 47 | f.cte.pMinus2 = pMinus2 48 | 49 | t := big.NewInt(16) 50 | pMod16 := t.Mod(f.p, t).Uint64() 51 | switch { 52 | case pMod16%4 == uint64(3): 53 | f.hasSqrt = generateSqrt3mod4(f) 54 | case pMod16%8 == uint64(5): 55 | f.hasSqrt = generateSqrt5mod8(f) 56 | case pMod16%16 == uint64(9): 57 | f.hasSqrt = generateSqrt9mod16(f) 58 | case pMod16%16 == uint64(1): 59 | f.hasSqrt = generateSqrt1mod16(f) 60 | } 61 | } 62 | 63 | func (f fp) String() string { return fmt.Sprintf("GF(%v)", f.name) } 64 | func (f fp) Zero() Elt { return &fpElt{big.NewInt(0)} } 65 | func (f fp) One() Elt { return &fpElt{big.NewInt(1)} } 66 | func (f fp) Rand(r io.Reader) Elt { e, _ := rand.Int(r, f.p); return &fpElt{e} } 67 | func (f fp) P() *big.Int { return new(big.Int).Set(f.p) } 68 | func (f fp) Order() *big.Int { return new(big.Int).Set(f.p) } 69 | func (f fp) Ext() uint { return uint(1) } 70 | func (f fp) BitLen() int { return f.p.BitLen() } 71 | func (f fp) Elt(in interface{}) Elt { 72 | var n *big.Int 73 | if v, ok := in.([]interface{}); ok && len(v) == 1 { 74 | n = FromType(v[0]) 75 | } else { 76 | n = FromType(in) 77 | } 78 | return f.mod(n) 79 | } 80 | func (f fp) mod(x *big.Int) Elt { return &fpElt{x.Mod(x, f.p)} } 81 | 82 | // Implementing hasPredicates 83 | 84 | func (f fp) IsZero(x Elt) bool { return x.(*fpElt).n.Sign() == 0 } 85 | func (f fp) AreEqual(x, y Elt) bool { return f.IsZero(f.Sub(x, y)) } 86 | func (f fp) IsSquare(x Elt) bool { return f.AreEqual(f.Exp(x, f.cte.pMinus1div2), f.One()) } 87 | func (f fp) IsEqual(ff Field) bool { return f.p.Cmp(ff.(fp).p) == 0 } 88 | 89 | // Implementing hasArith 90 | 91 | func (f fp) Neg(x Elt) Elt { return f.mod(new(big.Int).Neg(x.(*fpElt).n)) } 92 | func (f fp) Add(x, y Elt) Elt { return f.mod(new(big.Int).Add(x.(*fpElt).n, y.(*fpElt).n)) } 93 | func (f fp) Sub(x, y Elt) Elt { return f.mod(new(big.Int).Sub(x.(*fpElt).n, y.(*fpElt).n)) } 94 | func (f fp) Mul(x, y Elt) Elt { return f.mod(new(big.Int).Mul(x.(*fpElt).n, y.(*fpElt).n)) } 95 | func (f fp) Sqr(x Elt) Elt { return f.mod(new(big.Int).Mul(x.(*fpElt).n, x.(*fpElt).n)) } 96 | func (f fp) Inv(x Elt) Elt { return f.Exp(x, f.cte.pMinus2) } 97 | func (f fp) Exp(x Elt, y *big.Int) Elt { 98 | return &fpElt{new(big.Int).Exp(x.(*fpElt).n, y, f.p)} 99 | } 100 | 101 | // Implementing extended operations 102 | func (f fp) Generator() Elt { return f.One() } 103 | func (f fp) Inv0(x Elt) Elt { return f.Inv(x) } 104 | func (f fp) Sgn0(x Elt) int { return int(x.(*fpElt).n.Bit(0)) } 105 | func (f fp) CMov(x, y Elt, b bool) Elt { 106 | var z big.Int 107 | if b { 108 | z.Set(y.(*fpElt).n) 109 | } else { 110 | z.Set(x.(*fpElt).n) 111 | } 112 | return &fpElt{&z} 113 | } 114 | 115 | type sqrt3mod4 struct { 116 | *fp 117 | exp *big.Int 118 | } 119 | 120 | func generateSqrt3mod4(f *fp) hasSqrt { 121 | e := big.NewInt(1) 122 | e.Add(f.p, e) 123 | e.Rsh(e, 2) 124 | return sqrt3mod4{exp: e, fp: f} 125 | } 126 | 127 | func (s sqrt3mod4) Sqrt(x Elt) Elt { return s.Exp(x, s.exp) } 128 | 129 | type sqrt5mod8 struct { 130 | *fp 131 | sqrtOne *fpElt 132 | exp *big.Int 133 | } 134 | 135 | func generateSqrt5mod8(f *fp) hasSqrt { 136 | // Calculates c1 = sqrt(-1) mod p, for p=8*k+5 137 | // x(a) = -1 iff a^(4k+2) = -1 138 | // sqrt(-1) = sqrt(a^(4k+2)) 139 | // = a^(2k+1) 140 | // Since x(2) = -1, 2 \in QNR, then 141 | // sqrt(-1) = 2^(2k+1). 142 | k := big.NewInt(5) 143 | k.Sub(f.p, k) // p-5 144 | k.Rsh(k, 3) // k = (p-5)/8 145 | c1 := f.Exp(f.Elt(2), k) // c1 = 2^(k) 146 | c1 = f.Sqr(c1) // = 2^(2k) 147 | c1 = f.Add(c1, c1) // = 2^(2k+1) 148 | k.Add(k, big.NewInt(1)) // e = k+1 = (p+3)/8 149 | return sqrt5mod8{fp: f, exp: k, sqrtOne: c1.(*fpElt)} 150 | } 151 | 152 | func (s sqrt5mod8) Sqrt(x Elt) Elt { 153 | t0 := s.Exp(x, s.exp) 154 | t1 := s.Sqr(t0) 155 | e := s.AreEqual(x, t1) 156 | t1 = s.Mul(t0, s.sqrtOne) 157 | return s.CMov(t1, t0, e) 158 | } 159 | 160 | type sqrt9mod16 struct { 161 | *fp 162 | c1 *fpElt // c1 = sqrt(-1) in F, i.e., (c1^2) == -1 in F 163 | c2 *fpElt // c2 = sqrt(c1) in F, i.e., (c2^2) == c1 in F 164 | c3 *fpElt // c3 = sqrt(-c1) in F, i.e., (c3^2) == -c1 in F 165 | c4 *big.Int // c4 = (q + 7) / 16 # Integer arithmetic 166 | } 167 | 168 | func (s sqrt9mod16) Sqrt(x Elt) Elt { 169 | tv1 := s.Exp(x, s.c4) 170 | tv2 := s.Mul(s.c1, tv1) 171 | tv3 := s.Mul(s.c2, tv1) 172 | tv4 := s.Mul(s.c3, tv1) 173 | e1 := s.AreEqual(s.Sqr(tv2), x) 174 | e2 := s.AreEqual(s.Sqr(tv3), x) 175 | tv1 = s.CMov(tv1, tv2, e1) 176 | tv2 = s.CMov(tv4, tv3, e2) 177 | e3 := s.AreEqual(s.Sqr(tv2), x) 178 | return s.CMov(tv1, tv2, e3) 179 | } 180 | 181 | func generateSqrt9mod16(f *fp) hasSqrt { 182 | // Calculates c1 = sqrt(-1) mod p, for p=16*k+9 183 | // x(a) = -1 iff a^(8k+4) = -1 184 | // c1 = sqrt(-1) 185 | // = sqrt(a^(8k+4)) 186 | // = a^(4k+2) 187 | // c2 = sqrt(sqrt(-1)) 188 | // = sqrt(a^(4k+2)) 189 | // = a^(2k+1) 190 | // c3 = sqrt(-sqrt(-1)) 191 | // = sqrt(-1) * sqrt(-sqrt(-1)) 192 | // = c1*c2 193 | // 194 | // find a such that x(a) = -1. 195 | k := big.NewInt(9) 196 | k.Sub(f.p, k) // p-9 197 | k.Rsh(k, 4) // k = (p-9)/16 198 | a := findNonSquare(f) // a is QNR 199 | c2 := f.Exp(a, k) // c2 = a^(k) 200 | c2 = f.Sqr(c2) // = a^(2k) 201 | c2 = f.Mul(c2, a) // = a^(2k+1) 202 | c1 := f.Sqr(c2) // c1 = a^(4k+2) 203 | c3 := f.Mul(c1, c2) // c3 = c1*c2 204 | c4 := k.Add(k, big.NewInt(1)) // e = k+1 = (p+7)/16 205 | return sqrt9mod16{f, c1.(*fpElt), c2.(*fpElt), c3.(*fpElt), c4} 206 | } 207 | 208 | type sqrt1mod16 struct { 209 | *fp 210 | c1 *big.Int 211 | c3 *big.Int 212 | c5 *fpElt 213 | } 214 | 215 | func (s sqrt1mod16) Sqrt(x Elt) Elt { 216 | z := s.Exp(x, s.c3) 217 | t := s.Mul(s.Sqr(z), x) 218 | z = s.Mul(z, x) 219 | b := t.Copy() 220 | c := s.c5.Copy() 221 | 222 | one := big.NewInt(1) 223 | endInner := new(big.Int) 224 | for i := new(big.Int).Set(s.c1); i.Cmp(one) > 0; i.Sub(i, one) { 225 | endInner.Sub(i, one) 226 | for j := new(big.Int).Set(one); j.Cmp(endInner) < 0; j.Add(j, one) { 227 | b = s.Sqr(b) 228 | } 229 | z = s.CMov(z, s.Mul(z, c), !s.AreEqual(b, s.One())) 230 | c = s.Sqr(c).(*fpElt) 231 | t = s.CMov(t, s.Mul(t, c), !s.AreEqual(b, s.One())) 232 | b = t 233 | } 234 | 235 | return z 236 | } 237 | 238 | // Tonelli-Shanks algorithm. 239 | func generateSqrt1mod16(f *fp) hasSqrt { 240 | one := big.NewInt(1) 241 | two := big.NewInt(2) 242 | c1 := findC1(f) 243 | 244 | c2 := f.Order() 245 | c2.Sub(c2, one) 246 | c2.Div(c2, (&big.Int{}).Exp(two, c1, nil)) 247 | 248 | c3 := (&big.Int{}).Sub(c2, one) 249 | c3.Div(c3, two) 250 | 251 | c4 := findNonSquare(f) 252 | c5 := f.Exp(c4, c2).(*fpElt) 253 | 254 | return sqrt1mod16{fp: f, c1: c1, c3: c3, c5: c5} 255 | } 256 | 257 | // Find the largest integer c1 such that 2^c1 divides q-1 258 | func findC1(f *fp) *big.Int { 259 | zero := big.NewInt(0) 260 | one := big.NewInt(1) 261 | two := big.NewInt(2) 262 | 263 | c1 := big.NewInt(1) 264 | qMinus1 := (&big.Int{}).Sub(f.Order(), one) 265 | // loops until a valid c1 is found. 266 | for ; ; c1.Add(c1, one) { 267 | qMinus1.Div(qMinus1, two) 268 | if (&big.Int{}).Mod(qMinus1, two).Cmp(zero) == 1 { 269 | return c1 270 | } 271 | } 272 | } 273 | 274 | // Find a non square in the field 275 | func findNonSquare(f *fp) Elt { 276 | two := &fpElt{big.NewInt(2)} 277 | for i := two.Copy(); !f.AreEqual(i, f.Zero()); i = f.Add(i, f.One()) { 278 | if !f.IsSquare(i) { 279 | return i 280 | } 281 | } 282 | panic("no non-squares found") 283 | } 284 | -------------------------------------------------------------------------------- /field/fp2.go: -------------------------------------------------------------------------------- 1 | package field 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "math/big" 7 | "reflect" 8 | ) 9 | 10 | type fp2Elt [2]fpElt 11 | 12 | func (e fp2Elt) String() string { return fmt.Sprintf("\na: %v\nb: %v", e[0], e[1]) } 13 | func (e fp2Elt) Copy() Elt { return &fp2Elt{*(e[0].Copy().(*fpElt)), *(e[1].Copy().(*fpElt))} } 14 | func (e fp2Elt) Polynomial() []*big.Int { return append(e[0].Polynomial(), e[1].Polynomial()...) } 15 | 16 | type fp2 struct { 17 | hasSqrt 18 | base fp 19 | name string 20 | } 21 | 22 | // NewFp2 creates a quadratic extension field Z/pZ[x] with irreducible polynomial x^2=-1 and given p as an int, uint, *big.Int or string. 23 | func NewFp2(name string, p interface{}) Field { 24 | base := NewFp(name, p).(fp) 25 | f := fp2{base: base, name: name} 26 | f.precmp() 27 | return f 28 | } 29 | 30 | func (f *fp2) precmp() { 31 | t := big.NewInt(16) 32 | pMod16 := t.Mod(f.base.p, t).Uint64() 33 | switch { 34 | case pMod16%4 == uint64(3): 35 | f.hasSqrt = generateSqrtP3mod4(f) 36 | default: 37 | panic("not implemented yet") 38 | } 39 | } 40 | 41 | func (f fp2) Elt(in interface{}) Elt { 42 | 43 | v := reflect.ValueOf(in) 44 | 45 | if (v.Kind() == reflect.Slice || v.Kind() == reflect.Array) && v.Len() == 2 { 46 | return &fp2Elt{ 47 | *(f.base.Elt(v.Index(0).Interface()).(*fpElt)), 48 | *(f.base.Elt(v.Index(1).Interface()).(*fpElt)), 49 | } 50 | } 51 | 52 | return &fp2Elt{ 53 | *(f.base.Elt(in).(*fpElt)), 54 | *(f.base.Zero().(*fpElt)), 55 | } 56 | } 57 | func (f fp2) P() *big.Int { return f.base.P() } 58 | func (f fp2) Order() *big.Int { return new(big.Int).Mul(f.base.p, f.base.p) } 59 | func (f fp2) String() string { return "GF(" + f.name + ") Irred: i^2+1" } 60 | func (f fp2) Ext() uint { return uint(2) } 61 | func (f fp2) Zero() Elt { return f.Elt(0) } 62 | func (f fp2) One() Elt { return f.Elt(1) } 63 | func (f fp2) BitLen() int { return f.base.p.BitLen() } 64 | 65 | func (f fp2) AreEqual(x, y Elt) bool { return f.IsZero(f.Sub(x, y)) } 66 | func (f fp2) IsEqual(ff Field) bool { return f.base.p.Cmp(ff.(fp2).base.p) == 0 } 67 | func (f fp2) IsZero(x Elt) bool { 68 | e := x.(*fp2Elt) 69 | return f.base.IsZero(&e[0]) && f.base.IsZero(&e[1]) 70 | } 71 | func (f fp2) Rand(r io.Reader) Elt { 72 | return &fp2Elt{*f.base.Rand(r).(*fpElt), *f.base.Rand(r).(*fpElt)} 73 | } 74 | func (f fp2) Add(x, y Elt) Elt { 75 | xx := x.(*fp2Elt) 76 | yy := y.(*fp2Elt) 77 | z0 := f.base.Add(&xx[0], &yy[0]) 78 | z1 := f.base.Add(&xx[1], &yy[1]) 79 | return &fp2Elt{*(z0.(*fpElt)), *(z1.(*fpElt))} 80 | } 81 | func (f fp2) Sub(x, y Elt) Elt { 82 | xx := x.(*fp2Elt) 83 | yy := y.(*fp2Elt) 84 | z0 := f.base.Sub(&xx[0], &yy[0]) 85 | z1 := f.base.Sub(&xx[1], &yy[1]) 86 | return &fp2Elt{*(z0.(*fpElt)), *(z1.(*fpElt))} 87 | } 88 | 89 | func (f fp2) Mul(x, y Elt) Elt { 90 | xx := x.(*fp2Elt) 91 | yy := y.(*fp2Elt) 92 | x0y0 := f.base.Mul(&xx[0], &yy[0]) 93 | x0y1 := f.base.Mul(&xx[0], &yy[1]) 94 | x1y0 := f.base.Mul(&xx[1], &yy[0]) 95 | x1y1 := f.base.Mul(&xx[1], &yy[1]) 96 | 97 | z0 := f.base.Sub(x0y0, x1y1) 98 | z1 := f.base.Add(x0y1, x1y0) 99 | return &fp2Elt{*(z0.(*fpElt)), *(z1.(*fpElt))} 100 | } 101 | func (f fp2) Sqr(x Elt) Elt { return f.Mul(x, x) } 102 | func (f fp2) Inv(x Elt) Elt { 103 | xx := x.(*fp2Elt) 104 | tv1 := f.base.Sqr(&xx[0]) 105 | tv2 := f.base.Sqr(&xx[1]) 106 | tv3 := f.base.Add(tv1, tv2) 107 | tv4 := f.base.Inv(tv3) 108 | z0 := f.base.Mul(&xx[0], tv4) 109 | z1 := f.base.Mul(&xx[1], tv4) 110 | z1 = f.base.Neg(z1) 111 | return &fp2Elt{*(z0.(*fpElt)), *(z1.(*fpElt))} 112 | } 113 | func (f fp2) Neg(x Elt) Elt { 114 | xx := x.(*fp2Elt) 115 | z0 := f.base.Neg(&xx[0]) 116 | z1 := f.base.Neg(&xx[1]) 117 | return &fp2Elt{*(z0.(*fpElt)), *(z1.(*fpElt))} 118 | } 119 | func (f fp2) Exp(x Elt, e *big.Int) Elt { 120 | n := e.BitLen() 121 | z := f.One() 122 | for i := n - 1; i >= 0; i-- { 123 | z = f.Sqr(z) 124 | if e.Bit(i) == 1 { 125 | z = f.Mul(z, x) 126 | } 127 | } 128 | return z 129 | } 130 | func (f fp2) IsSquare(x Elt) bool { 131 | xx := x.(*fp2Elt) 132 | tv1 := f.base.Sqr(&xx[0]) 133 | tv2 := f.base.Sqr(&xx[1]) 134 | tv3 := f.base.Add(tv1, tv2) 135 | tv4 := f.base.Exp(tv3, f.base.cte.pMinus1div2) 136 | return f.base.AreEqual(tv4, f.base.One()) 137 | } 138 | 139 | func (f fp2) Generator() Elt { return f.Elt([]string{"0", "1"}) } 140 | func (f fp2) Inv0(x Elt) Elt { return f.Inv(x) } 141 | func (f fp2) CMov(x, y Elt, b bool) Elt { 142 | xx := x.(*fp2Elt) 143 | yy := y.(*fp2Elt) 144 | z0 := f.base.CMov(&xx[0], &yy[0], b) 145 | z1 := f.base.CMov(&xx[1], &yy[1], b) 146 | return &fp2Elt{*(z0.(*fpElt)), *(z1.(*fpElt))} 147 | } 148 | func (f fp2) Sgn0(x Elt) int { 149 | xx := x.(*fp2Elt) 150 | s0 := f.base.Sgn0(&xx[0]) 151 | z0 := 0 152 | if f.base.IsZero(&xx[0]) { 153 | z0 = 1 154 | } 155 | s1 := f.base.Sgn0(&xx[1]) 156 | return s0 | (z0 & s1) 157 | } 158 | 159 | type f2sqrtp3mod4 struct { 160 | // This Alg 9. from Adj-Rodriguez 161 | *fp2 162 | c1 *big.Int // c1 = (p-3)/4 163 | c2 *big.Int // c2 = (p-1)/2 164 | } 165 | 166 | func generateSqrtP3mod4(f *fp2) hasSqrt { 167 | c1 := big.NewInt(3) 168 | c1.Sub(f.base.p, c1) 169 | c1.Rsh(c1, 2) 170 | c2 := big.NewInt(1) 171 | c2.Sub(f.base.p, c2) 172 | c2.Rsh(c2, 1) 173 | return f2sqrtp3mod4{c1: c1, c2: c2, fp2: f} 174 | } 175 | 176 | func (s f2sqrtp3mod4) Sqrt(a Elt) Elt { 177 | a1 := s.Exp(a, s.c1) 178 | a1a := s.Mul(a1, a) 179 | alpha := s.Mul(a1, a1a) 180 | x0 := a1a 181 | 182 | var zz Elt 183 | if t := s.Add(alpha, s.One()); s.IsZero(t) { 184 | i := &fp2Elt{ 185 | *(s.base.Zero().(*fpElt)), 186 | *(s.base.One().(*fpElt)), 187 | } 188 | zz = s.Mul(x0, i) 189 | } else { 190 | par := s.Add(s.One(), alpha) 191 | b := s.Exp(par, s.c2) 192 | zz = s.Mul(b, x0) 193 | } 194 | return zz 195 | } 196 | -------------------------------------------------------------------------------- /field/fp2_test.go: -------------------------------------------------------------------------------- 1 | package field_test 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | GF "github.com/armfazh/tozan-ecc/field" 8 | ) 9 | 10 | func TestGeneratorF2(t *testing.T) { 11 | // Field taken from https://github.com/armfazh/h2c-go-ref/blob/master/field/fields.go 12 | F := GF.NewFp2("BN254G2", "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47") 13 | F.Generator() 14 | } 15 | 16 | func TestSqrtF2(t *testing.T) { 17 | var primes3mod4 = []int{59, 67, 71, 79, 83} 18 | for _, p := range primes3mod4 { 19 | testSqrtF2(t, p) 20 | } 21 | } 22 | 23 | func testSqrtF2(t *testing.T, p int) { 24 | F := GF.NewFp2(fmt.Sprintf("%v", p), p) 25 | for i := 0; i < p; i++ { 26 | for j := 0; j < p; j++ { 27 | x := F.Elt([]interface{}{i, j}) 28 | if F.IsSquare(x) { 29 | y := F.Sqrt(x) 30 | got := F.Sqr(y) 31 | want := x 32 | if !F.AreEqual(got, want) { 33 | t.Fatalf("got: %v\nwant: %v\n%v\nF:%v", got, want, i, F) 34 | } 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /field/fp_test.go: -------------------------------------------------------------------------------- 1 | package field_test 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | GF "github.com/armfazh/tozan-ecc/field" 8 | ) 9 | 10 | func TestSqrt(t *testing.T) { 11 | var primes = []int{ 12 | 607, // 3 mod 4 13 | 613, // 5 mod 8 14 | 617, // 9 mod 16 15 | 641, // 1 mod 16 16 | } 17 | for _, p := range primes { 18 | testSqrt(t, p) 19 | } 20 | } 21 | 22 | func testSqrt(t *testing.T, p int) { 23 | F := GF.NewFp(fmt.Sprintf("%v", p), p) 24 | for i := 0; i < p; i++ { 25 | x := F.Elt(i) 26 | if F.IsSquare(x) { 27 | y := F.Sqrt(x) 28 | got := F.Sqr(y) 29 | want := x 30 | if !F.AreEqual(got, want) { 31 | t.Fatalf("got: %v\nwant: %v\nF:%v", got, want, F) 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /field/int.go: -------------------------------------------------------------------------------- 1 | package field 2 | 3 | import ( 4 | "fmt" 5 | "math/big" 6 | ) 7 | 8 | // FromType converts an int, uint or string to a big.Int. 9 | func FromType(in interface{}) *big.Int { 10 | n := new(big.Int) 11 | switch s := in.(type) { 12 | case *big.Int: 13 | n.Set(s) 14 | case big.Int: 15 | n.Set(&s) 16 | case string: 17 | if _, ok := n.SetString(s, 0); !ok { 18 | panic("error setting the number") 19 | } 20 | case uint: 21 | n.SetUint64(uint64(s)) 22 | case uint8: 23 | n.SetUint64(uint64(s)) 24 | case uint16: 25 | n.SetUint64(uint64(s)) 26 | case uint32: 27 | n.SetUint64(uint64(s)) 28 | case uint64: 29 | n.SetUint64(uint64(s)) 30 | case int: 31 | n.SetInt64(int64(s)) 32 | case int8: 33 | n.SetInt64(int64(s)) 34 | case int16: 35 | n.SetInt64(int64(s)) 36 | case int32: 37 | n.SetInt64(int64(s)) 38 | case int64: 39 | n.SetInt64(int64(s)) 40 | default: 41 | panic(fmt.Errorf("type %T not supported", in)) 42 | } 43 | return n 44 | } 45 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/armfazh/tozan-ecc 2 | 3 | go 1.13 4 | --------------------------------------------------------------------------------