• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

famoser / elliptic / 16238185638

12 Jul 2025 12:51PM UTC coverage: 84.857% (-6.3%) from 91.134%
16238185638

Pull #12

github

web-flow
Merge 3f795b2e3 into 5ce1049c0
Pull Request #12: WIP: Add montgomery

270 of 376 new or added lines in 17 files covered. (71.81%)

2 existing lines in 1 file now uncovered.

947 of 1116 relevant lines covered (84.86%)

23.02 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/Serializer/PointDecoder/MGPointDecoder.php
1
<?php
2

3
namespace Famoser\Elliptic\Serializer\PointDecoder;
4

5
use Famoser\Elliptic\Primitives\Curve;
6
use Famoser\Elliptic\Primitives\CurveType;
7
use Famoser\Elliptic\Primitives\Point;
8

9
class MGPointDecoder
10
{
NEW
11
    public function __construct(private readonly Curve $curve)
×
12
    {
13
        // check allowed to use this decoder
NEW
14
        $check = $curve->getType() === CurveType::Montgomery;
×
NEW
15
        if (!$check) {
×
NEW
16
            throw new \AssertionError('Cannot use this decoder with the chosen curve.');
×
17
        }
18
    }
19

20
    /**
21
     * @throws PointDecoderException
22
     */
NEW
23
    public function fromCoordinates(\GMP $x, \GMP $y): Point
×
24
    {
NEW
25
        $point = new Point($x, $y);
×
26

NEW
27
        if (!$this->fulfillsDefiningEquation($point)) {
×
NEW
28
            throw new PointDecoderException('Point not on curve.');
×
29
        }
30

NEW
31
        return $point;
×
32
    }
33

34
    /**
35
     * implements https://datatracker.ietf.org/doc/html/rfc8032#section-5.1.1
36
     * @throws PointDecoderException
37
     */
NEW
38
    public function fromXCoordinate(\GMP $x): Point
×
39
    {
NEW
40
        $p = $this->curve->getP();
×
NEW
41
        if (gmp_cmp(gmp_mod($p, 8), 5) !== 0) {
×
NEW
42
            throw new PointDecoderException('Point decoding for p mod 8 != 5 not implemented.');
×
43
        }
44

NEW
45
        $alpha = gmp_mod($this->calculateComparand($x), $p);
×
46

47
        /*
48
         * take the square root of alpha, while doing a (much cheaper) exponentiation
49
         *
50
         * observe that alpha^((p+3)/8) = y^((p+3)/4) = candidate
51
         * (p+3)/8 is an integer, as for our prime p it holds that p mod 8 = 5
52
         */
NEW
53
        $const = gmp_div(gmp_add($p, 3), 8);
×
NEW
54
        $candidate = gmp_powm($alpha, $const, $p);
×
55

NEW
56
        $candidateSquare = gmp_powm($candidate, 2, $p);
×
NEW
57
        if (gmp_cmp($candidateSquare, $alpha) === 0) {
×
NEW
58
            return new Point($x, $candidate);
×
59
        } else {
NEW
60
            $check = gmp_mod(gmp_add($candidateSquare, $alpha), $p);
×
NEW
61
            if (gmp_cmp($check, 0) === 0) {
×
NEW
62
                $const = gmp_div(gmp_sub($p, 1), 4);
×
NEW
63
                $correctionFactor = gmp_powm(2, $const, $p);
×
NEW
64
                $correctedCandidate = gmp_mod(gmp_mul($candidate, $correctionFactor), $p);
×
65

NEW
66
                return new Point($x, $correctedCandidate);
×
67
            }
68

NEW
69
            throw new PointDecoderException('No square root of alpha.');
×
70
        }
71
    }
72

73
    /**
74
     * montgomery defined by by^2 = x^3 + ax^2 + x
75
     */
NEW
76
    private function fulfillsDefiningEquation(Point $point): bool
×
77
    {
NEW
78
        $left = gmp_mul(
×
NEW
79
            $this->curve->getB(),
×
NEW
80
            gmp_pow($point->y, 2)
×
NEW
81
        );
×
82

NEW
83
        $right = $this->calculateComparand($point->x);
×
84

NEW
85
        $comparison = gmp_mod(
×
NEW
86
            gmp_sub($left, $right),
×
NEW
87
            $this->curve->getP()
×
NEW
88
        );
×
89

NEW
90
        return gmp_cmp($comparison, 0) == 0;
×
91
    }
92

93
    /**
94
     * calculate x^3 + ax^2 + x
95
     */
NEW
96
    private function calculateComparand(\GMP $x): \GMP
×
97
    {
NEW
98
        return gmp_add(
×
NEW
99
            gmp_add(
×
NEW
100
                gmp_powm($x, 3, $this->curve->getP()),
×
NEW
101
                gmp_mul(
×
NEW
102
                    $this->curve->getA(),
×
NEW
103
                    gmp_pow($x, 2)
×
NEW
104
                )
×
NEW
105
            ),
×
NEW
106
            $x
×
NEW
107
        );
×
108
    }
109
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc