package curve import ( "errors" "fmt" "log" "math/big" ) var ( MinP = big.NewInt(11) ) // 4a³ + 27b² = 0 - проверка кривой на сингулярность func New(a, b *big.Int) (*Curve, error) { c := &Curve{ a: new(big.Int).Set(a), b: new(big.Int).Set(b), } return c, c.IsSingular() } type Curve struct { a *big.Int // константа a b *big.Int // константа b p *big.Int // размер конечного поля g *Point // базовая точка подгруппы n *big.Int // порядок подгруппы h *big.Int // кофактор подгруппы } func (s *Curve) A() (res *big.Int) { return intCopy(s.a) } func (s *Curve) B() (res *big.Int) { return intCopy(s.b) } // Проверка, установлен ли размер конечного поля func (s *Curve) IsValidP() (err error) { if err = s.IsValidConstants(); err == nil { if s.p == nil { err = errors.New("размер конечного поля не установлен") } } return } func (s *Curve) IsValidG() (err error) { if err = s.IsValidP(); err == nil { if s.g == nil { err = errors.New("базовая точка подгруппы g не определена") } } return } func (s *Curve) IsValidN() (err error) { if err = s.IsValidG(); err == nil { if s.n == nil { err = errors.New("порядок подгруппы не определен") } } return } // Возвращает строку уравнения кривой func (s *Curve) FormulaString() string { return fmt.Sprintf( "y² = x³ + %sx + %s", mustBigInt(s.a), mustBigInt(s.b), ) } // Проверка кривой на сингулярность (4a³ + 27b² = 0) func (s *Curve) IsSingular() (err error) { if err = s.IsValidConstants(); err != nil { return } l := new(big.Int).Mul(new(big.Int).Exp(s.a, big.NewInt(3), nil), big.NewInt(4)) r := new(big.Int).Mul(new(big.Int).Exp(s.b, big.NewInt(2), nil), big.NewInt(27)) if l.Add(l, r).Cmp(big.NewInt(0)) == 0 { err = fmt.Errorf("кривая [ %s ] сингулярна и не рекомендуется к использованию", s.FormulaString()) } return } // Проверка констант уравнения на валидность func (s *Curve) IsValidConstants() error { if s.a == nil { return errors.New("константа [ a ] не определена") } if s.b == nil { return errors.New("константа [ b ] не определена") } return nil } // Установка размера конечного поля func (s *Curve) SetP(p *big.Int) (err error) { if s.p != nil { return errors.New("резмер конечного поля уже определен") } if err = s.IsValidConstants(); err != nil { return } if !IsPrime(p) { err = fmt.Errorf("число [ %s ] не является простым. Размер конечного поля должен быть простым числом", p) return } s.p = p /*if !IsPrime(Div(Sub(p, 1), 2)) { }*/ /* if p.Cmp(MinP) < 0 { err = fmt.Errorf("слишком маленький размер конечного поля [ %s ]", p) return } */ //s.p = new(big.Int).Set(p) // сброс подгруппы s.n = nil s.h = nil return } func (s *Curve) Point(x, y *big.Int) *Point { return NewPoint(x, y, s) } func (s *Curve) InverseMod(k, p *big.Int) (res *big.Int, err error) { if err = s.IsValidP(); err != nil { return } if k == nil { err = errors.New("[ k ] не определено") return } else if rk := k.Cmp(intZero); rk == 0 { err = errors.New("[ k ] == 0. Деление на 0 невозможно") return } else if rk < 0 { // k ** -1 = p - (-k) ** -1 (mod p) // point - self.inverseMod(-k, point) var iMod *big.Int if iMod, err = s.InverseMod(Neg(k), p); err == nil { res = Sub(p, iMod) } } else { s, olds := big.NewInt(0), big.NewInt(1) t, oldt := big.NewInt(1), big.NewInt(0) r, oldr := intCopy(p), intCopy(k) for r.Cmp(intZero) != 0 { quot := Div(oldr, r) oldr, r = r, Sub(oldr, Mul(quot, r)) olds, s = s, Sub(olds, Mul(quot, s)) oldt, t = t, Sub(oldt, Mul(quot, t)) } // gcd, x, y = old_r, old_s, old_t res = Mod(olds, p) } return } // Определение координат пары зеркальных точек по x func (s *Curve) points(dx *big.Int) (p1, p2 *Point, err error) { dxx := intCopy(dx) // Инициализируем результирующие точки пустыми p1, p2 = s.Point(nil, nil), s.Point(nil, nil) var dy *big.Int // Операции, обратной делению по модулю, не существует, поэтому // для определения координаты по y, необходимо, путем перебора с подстановкой y, // проверить равенство левой части уравнения, разделенного по модулю на p с // правой частью, так же разделенной по модулю на p for i := big.NewInt(0); i.Cmp(s.p) < 0; i.Add(i, big.NewInt(1)) { // i ** 2 % s.p == (dx ** 3 + s.a * dx + self.b) % self.p > 0 l := Mod(Exp64(i, 2), s.p) r := Mod( Add( Exp64(dx, 3), Add( Mul(s.a, dx), s.b, ), ), s.p, ) if l.Cmp(r) == 0 { dy = i break } } if dy == nil { err = fmt.Errorf("не удалось найти пару зеркальных точек на кривой после x [ %s ]", dxx) } else { p1.x, p1.y = dx, dy p2.x = intCopy(p1.x) p2.y = Mod(Neg(p1.y), s.p) } return } func (s *Curve) searhClosePoints(x *big.Int) (p1, p2 *Point, err error) { cx := intCopy(x) if x.Cmp(s.p) >= 0 { x = Sub(s.p, big.NewInt(1)) } else if x.Cmp(intZero) < 0 { x = big.NewInt(0) } //kx := Sub64(x, 1) kx := intCopy(x) for { //log.Println("xkx", x, kx) if x.Cmp(s.p) >= 0 && kx.Cmp(intZero) <= 0 { err = fmt.Errorf("не удалось найти точки, близкие к [ %s ]", cx) break } else { // Поиск вправо if x.Cmp(s.p) <= 0 { if p1, p2, err = s.points(x); err == nil { if p1.IsInCurve() == nil { return } } x = Add64(x, 1) } // Поиск влево if kx.Cmp(intZero) < 0 { if p1, p2, err = s.points(kx); err == nil { if p1.IsInCurve() == nil { return } } kx = Sub64(kx, 1) } } } return } func (s *Curve) SetG(g *Point) (err error) { if s.g != nil { err = errors.New("базовая точка подгруппы g уже определена") return } if err = s.IsValidP(); err != nil { return } if err = g.IsInCurve(); err == nil && g.curve == s { s.g = g } return } func (s *Curve) SetGRandom() (err error) { if s.g != nil { err = errors.New("базовая точка подгруппы g уже определена") return } if err = s.IsValidP(); err != nil { return } x := Random( Div(s.p, big.NewInt(2)), Sub(s.p, big.NewInt(10)), ) //log.Println(x) p1, p2, err := s.searhClosePoints(x) if err != nil { return } if err = p1.IsInCurve(); err == nil { s.g = p1 } else if err = p2.IsInCurve(); err == nil { s.g = p2 } else { err = errors.New("не удалось найти точку g, пренадлежащую кривой") } return } // Поиск порядка подгруппы func (s *Curve) SetN() (err error) { if s.n != nil { return errors.New("порядок подгруппы уже определен") } if err = s.IsValidP(); err != nil { return } dx, dy := intCopy(s.g.x), Mod(Neg(s.g.y), s.p) tmpG := s.g.Copy() s.n = big.NewInt(1) for { s.n.Add(s.n, big.NewInt(1)) if tmpG, err = tmpG.Add(s.g); err != nil { return } if tmpG.x.Cmp(dx) == 0 && tmpG.y.Cmp(dy) == 0 { s.n.Add(s.n, big.NewInt(1)) return } } } func (s *Curve) KeyPub(priv *big.Int) (pub *Point, err error) { if err = s.IsValidN(); err != nil { return } pub, err = s.g.Mul(priv) return } func (s *Curve) RandomKeyPair() (priv *big.Int, pub *Point, err error) { if err = s.IsValidN(); err != nil { return } priv = Random(big.NewInt(1), Sub64(s.n, 1)) pub, err = s.g.Mul(priv) return } // Вычисление общего секрета func (s *Curve) PointSecret(mPriv *big.Int, fPub *Point) (res *Point, err error) { if err = s.IsValidN(); err != nil { return } res, err = fPub.Mul(mPriv) return } type ELKeyPriv struct { d *big.Int } type ELKeyPub struct { e1 *Point e2 *Point } type ELKeyPair struct { curve *Curve priv *ELKeyPriv pub *ELKeyPub dTable map[byte]*Point } func (s *ELKeyPair) setupDataTable() error { if s.dTable != nil { return nil } s.dTable = make(map[byte]*Point) dx := big.NewInt(0) //var points []*Point //var p *Point for i := byte(0); i <= 254; i++ { p, _, err := s.curve.searhClosePoints(dx) if err != nil { return err } // check already exists - todo dx = Add64(p.x, 1) s.dTable[i] = p log.Println(i, p) } return nil } type ELMessage struct { c1 *Point cd []*Point } // c1 = r x e1 // c2 = P + r x e2 func (s *ELKeyPair) EncodeMessage(data []byte) (mes *ELMessage, err error) { r := Random(big.NewInt(1), Sub64(s.curve.p, 1)) c1, err := s.pub.e1.Mul(r) if err != nil { return nil, err } mes = &ELMessage{ c1: c1, cd: make([]*Point, len(data)), } for i, d := range data { p := s.dTable[d] c2, err := s.pub.e2.Mul(r) if err != nil { return nil, err } cd, err := p.Add(c2) if err != nil { return nil, err } mes.cd[i] = cd } return mes, nil } // p = c2 – (d x c1) func (s *ELKeyPair) DecodeMessage(mes *ELMessage) ([]byte, error) { res := make([]byte, len(mes.cd)) part, err := mes.c1.Mul(s.priv.d) if err != nil { return nil, err } part, _ = part.Neg() for _, c2 := range mes.cd { p, err := c2.Add(part) if err != nil { return nil, err } log.Println(p) } return res, nil } // https://intuit.ru/studies/professional_retraining/940/courses/408/lecture/9373?page=6 func (s *Curve) ELKeyPair() (*ELKeyPair, error) { e1, _, err := s.searhClosePoints(Random(big.NewInt(1), Sub64(s.p, 1))) if err != nil { return nil, err } d := Random(big.NewInt(1), Sub64(s.n, 1)) e2, err := e1.Mul(d) if err != nil { return nil, err } res := &ELKeyPair{ curve: s, priv: &ELKeyPriv{ d: d, }, pub: &ELKeyPub{ e1: e1, e2: e2, }, } return res, res.setupDataTable() } /* func (s *Curve) HEncode(b byte, pub *Point) (cm1, cm2 *Point, err error) { var p1 *Point if p1, _, err = s.points(big.NewInt(int64(b))); err != nil { return } c1 = pub.Add() } */ /* // 𝐶𝑚 = (𝑘 × 𝐺, 𝑃𝑚 + 𝑘 × 𝑃𝐵) func (s *Curve) HellmanEncode(b byte, pub *Point) (cm1, cm2 *Point, err error) { k := Random(big.NewInt(1), Sub64(s.n, 1)) if cm1, err = s.g.Mul(k); err != nil { return } cm2, err = pub.Mul(Add64(k, int64(b))) return } */ /* func (s *Curve) HellmanDecode(cm1, cm2 *Point, priv *big.Int) { } */