Elliptic curve arithmetic: Difference between revisions

m
m (→‎{{header|REXX}}: simplified the ROOTi function.)
m (→‎{{header|Wren}}: Minor tidy)
 
(43 intermediate revisions by 24 users not shown)
Line 1:
{{draft task}}
[[wp:Elliptic curve|Elliptic curve]]s are sometimes used in [[wp:cryptography|cryptography]] as a way to perform [[wp:digital signature|digital signature]]s. The purpose of this task is to implement a simplified (without modular arithmetic) version of the elliptic curve arithmetic which is required by the [[wp:ECDSA|elliptic curve DSA]] protocol.
 
[[wp:Elliptic curve|Elliptic curve]]s   are sometimes used in   [[wp:cryptography|cryptography]]   as a way to perform   [[wp:digital signature|digital signature]]s.
In a nutshell, an elliptic curve is a bi-dimensional curve defined by the following relation between the x and y coordinates of any point on the curve:
 
The purpose of this task is to implement a simplified (without modular arithmetic) version of the elliptic curve arithmetic which is required by the   [[wp:ECDSA|elliptic curve DSA]]   protocol.
<math>y^2 = x^3 + a x + b</math>
 
In a nutshell, an elliptic curve is a bi-dimensional curve defined by the following relation between the '''x''' and '''y''' coordinates of any point on the curve:
a and b are arbitrary parameters that define the specific curve which is used. For this particular task, we'll use the following parameters:
 
:::: &nbsp; <big><big><math>y^2 = x^3 + a x + b</math></big></big>
a=0, b=7
 
'''a''' and '''b''' are arbitrary parameters that define the specific curve which is used.
The most interesting thing about elliptic curves is the fact that it is possible to define a [[wp:group|group]] structure on it. To do so we define an [[wp:internal composition|internal composition]] rule with an additive notation ''+'', such that for any three distinct points P, Q and R on the curve, whenever these points are aligned, we have:
 
For this particular task, we'll use the following parameters:
P + Q + R = 0
 
:::: &nbsp; <big> a=0<b>,</b> &nbsp; b=7 </big>
Here 0 is the ''infinity point'', for which the x and y values are not defined. It's basically the same kind of point which defines the horizon in [[wp:projective geometry|projective geometry]]. We'll also assume here that this infinity point is unique and defines the [[wp:identity element|neutral element]] of the addition.
 
The most interesting thing about elliptic curves is the fact that it is possible to define a &nbsp; [[wp:group|group]] &nbsp; structure on it.
This was not the definition of the addition, but only its desired property. For a more accurate definition, we proceed as such:
 
To do so we define an &nbsp; [[wp:internal composition|internal composition]] &nbsp; rule with an additive notation '''+''', &nbsp; such that for any three distinct points '''P''', '''Q''' and '''R''' on the curve, whenever these points are aligned, we have:
Given any three aligned points P, Q and R, we define the sum S = P + Q as the point (possibly the infinity point) such that S, R and the infinity point are aligned.
 
:::: &nbsp; <big> P + Q + R = 0 </big>
Considering the symmetry of the curve around the x-axis, it's easy to convince oneself that two points S and R can be aligned with the infinity point if and only if S and R are symmetric of one another towards the x-axis (because in that case there is no other candidate than the infinity point to complete the alignment triplet).
 
Here &nbsp; <big>'''0'''</big> &nbsp; (zero) &nbsp; is the ''infinity point'', &nbsp; for which the '''x''' and '''y''' values are not defined. &nbsp; It's basically the same kind of point which defines the horizon in &nbsp; [[wp:projective geometry|projective geometry]].
S is thus defined as the symmetric of R towards the x axis.
 
We'll also assume here that this infinity point is unique and defines the &nbsp; [[wp:identity element|neutral element]] &nbsp; of the addition.
The task consists in defining the addition which, for any two points of the curve, returns the sum of these two points. You will pick two random points on the curve, compute their sum and show that the symmetric of the sum is aligned with the two initial points.
 
This was not the definition of the addition, but only its desired property. &nbsp; For a more accurate definition, we proceed as such:
You will use the a and b parameters of secp256k1, i.e. respectively zero and seven.
 
Given any three aligned points '''P''', '''Q''' and '''R''', &nbsp; we define the sum &nbsp; '''S = P + Q''' &nbsp; as the point (possibly the infinity point) such that &nbsp; '''S''', '''R''' &nbsp; and the infinity point are aligned.
''Hint'': You might need to define a "doubling" function, that returns P+P for any given point P.
 
Considering the symmetry of the curve around the x-axis, it's easy to convince oneself that two points '''S''' and '''R''' can be aligned with the infinity point if and only if '''S''' and '''R''' are symmetric of one another towards the x-axis &nbsp; (because in that case there is no other candidate than the infinity point to complete the alignment triplet).
''Extra credit'': define the full elliptic curve arithmetic (still not modular, though) by defining a "multiply" function that returns, for any point P and integer n, the point P + P + ... + P (n times).
 
'''S''' is thus defined as the symmetric of '''R''' towards the '''x''' axis.
 
The task consists in defining the addition which, for any two points of the curve, returns the sum of these two points. &nbsp; You will pick two random points on the curve, compute their sum and show that the symmetric of the sum is aligned with the two initial points.
 
You will use the '''a''' and '''b''' parameters of secp256k1, i.e. respectively zero and seven.
 
''Hint'': &nbsp; You might need to define a "doubling" function, that returns '''P+P''' for any given point '''P'''.
 
''Extra credit'': &nbsp; define the full elliptic curve arithmetic (still not modular, though) by defining a "multiply" function that returns,
<br>for any point '''P''' and integer '''n''', &nbsp; the point '''P + P + ... + P''' &nbsp; &nbsp; ('''n''' times).
<br><br>
 
=={{header|11l}}==
{{trans|Python}}
 
<syntaxhighlight lang="11l">T Point
:b = 7
 
Float x, y
 
F (x = Float.infinity, y = Float.infinity)
.x = x
.y = y
 
F.const copy()
R Point(.x, .y)
 
F.const is_zero()
R .x > 1e20 | .x < -1e20
 
F neg()
R Point(.x, -.y)
 
F dbl()
I .is_zero()
R .copy()
I .y == 0
R Point()
V l = (3 * .x * .x) / (2 * .y)
V x = l * l - 2 * .x
R Point(x, l * (.x - x) - .y)
 
F add(q)
I .x == q.x & .y == q.y
R .dbl()
I .is_zero()
R q.copy()
I q.is_zero()
R .copy()
I q.x - .x == 0
R Point()
V l = (q.y - .y) / (q.x - .x)
V x = l * l - .x - q.x
R Point(x, l * (.x - x) - .y)
 
F mul(n)
V p = .copy()
V r = Point()
V i = 1
L i <= n
I i [&] n
r = r.add(p)
p = p.dbl()
i <<= 1
R r
 
F String()
R ‘(#.3, #.3)’.format(.x, .y)
 
F show(s, p)
print(s‘ ’(I p.is_zero() {‘Zero’} E p))
 
F from_y(y)
V n = y * y - Point.:b
V x = I n >= 0 {n ^ (1. / 3)} E -((-n) ^ (1. / 3))
R Point(x, y)
 
V a = from_y(1)
V b = from_y(2)
show(‘a =’, a)
show(‘b =’, b)
V c = a.add(b)
show(‘c = a + b =’, c)
V d = c.neg()
show(‘d = -c =’, d)
show(‘c + d =’, c.add(d))
show(‘a + b + d =’, a.add(b.add(d)))
show(‘a * 12345 =’, a.mul(12345))</syntaxhighlight>
 
{{out}}
<pre>
a = (-1.817, 1.000)
b = (-1.442, 2.000)
c = a + b = (10.375, -33.525)
d = -c = (10.375, 33.525)
c + d = Zero
a + b + d = Zero
a * 12345 = (10.759, 35.387)
</pre>
 
=={{header|C}}==
<langsyntaxhighlight lang="c">#include <stdio.h>
#include <math.h>
 
Line 106 ⟶ 205:
 
return 0;
}</langsyntaxhighlight>
{{out}}
<pre>
Line 116 ⟶ 215:
a + b + d = Zero
a * 12345 = (10.759, 35.387)
</pre>
 
=={{header|C++}}==
Uses C++11 or later
<syntaxhighlight lang="cpp">#include <cmath>
#include <iostream>
 
using namespace std;
 
// define a type for the points on the elliptic curve that behaves
// like a built in type.
class EllipticPoint
{
double m_x, m_y;
static constexpr double ZeroThreshold = 1e20;
static constexpr double B = 7; // the 'b' in y^2 = x^3 + a * x + b
// 'a' is 0
void Double() noexcept
{
if(IsZero())
{
// doubling zero is still zero
return;
}
// based on the property of the curve, the line going through the
// current point and the negative doubled point is tangent to the
// curve at the current point. wikipedia has a nice diagram.
if(m_y == 0)
{
// at this point the tangent to the curve is vertical.
// this point doubled is 0
*this = EllipticPoint();
}
else
{
double L = (3 * m_x * m_x) / (2 * m_y);
double newX = L * L - 2 * m_x;
m_y = L * (m_x - newX) - m_y;
m_x = newX;
}
}
public:
friend std::ostream& operator<<(std::ostream&, const EllipticPoint&);
 
// Create a point that is initialized to Zero
constexpr EllipticPoint() noexcept : m_x(0), m_y(ZeroThreshold * 1.01) {}
 
// Create a point based on the yCoordiante. For a curve with a = 0 and b = 7
// there is only one x for each y
explicit EllipticPoint(double yCoordinate) noexcept
{
m_y = yCoordinate;
m_x = cbrt(m_y * m_y - B);
}
 
// Check if the point is 0
bool IsZero() const noexcept
{
// when the elliptic point is at 0, y = +/- infinity
bool isNotZero = abs(m_y) < ZeroThreshold;
return !isNotZero;
}
 
// make a negative version of the point (p = -q)
EllipticPoint operator-() const noexcept
{
EllipticPoint negPt;
negPt.m_x = m_x;
negPt.m_y = -m_y;
return negPt;
}
 
// add a point to this one ( p+=q )
EllipticPoint& operator+=(const EllipticPoint& rhs) noexcept
{
if(IsZero())
{
*this = rhs;
}
else if (rhs.IsZero())
{
// since rhs is zero this point does not need to be
// modified
}
else
{
double L = (rhs.m_y - m_y) / (rhs.m_x - m_x);
if(isfinite(L))
{
double newX = L * L - m_x - rhs.m_x;
m_y = L * (m_x - newX) - m_y;
m_x = newX;
}
else
{
if(signbit(m_y) != signbit(rhs.m_y))
{
// in this case rhs == -lhs, the result should be 0
*this = EllipticPoint();
}
else
{
// in this case rhs == lhs.
Double();
}
}
}
 
return *this;
}
 
// subtract a point from this one (p -= q)
EllipticPoint& operator-=(const EllipticPoint& rhs) noexcept
{
*this+= -rhs;
return *this;
}
// multiply the point by an integer (p *= 3)
EllipticPoint& operator*=(int rhs) noexcept
{
EllipticPoint r;
EllipticPoint p = *this;
 
if(rhs < 0)
{
// change p * -rhs to -p * rhs
rhs = -rhs;
p = -p;
}
for (int i = 1; i <= rhs; i <<= 1)
{
if (i & rhs) r += p;
p.Double();
}
 
*this = r;
return *this;
}
};
 
// add points (p + q)
inline EllipticPoint operator+(EllipticPoint lhs, const EllipticPoint& rhs) noexcept
{
lhs += rhs;
return lhs;
}
 
// subtract points (p - q)
inline EllipticPoint operator-(EllipticPoint lhs, const EllipticPoint& rhs) noexcept
{
lhs += -rhs;
return lhs;
}
 
// multiply by an integer (p * 3)
inline EllipticPoint operator*(EllipticPoint lhs, const int rhs) noexcept
{
lhs *= rhs;
return lhs;
}
 
// multiply by an integer (3 * p)
inline EllipticPoint operator*(const int lhs, EllipticPoint rhs) noexcept
{
rhs *= lhs;
return rhs;
}
 
 
// print the point
ostream& operator<<(ostream& os, const EllipticPoint& pt)
{
if(pt.IsZero()) cout << "(Zero)\n";
else cout << "(" << pt.m_x << ", " << pt.m_y << ")\n";
return os;
}
 
int main(void) {
const EllipticPoint a(1), b(2);
cout << "a = " << a;
cout << "b = " << b;
const EllipticPoint c = a + b;
cout << "c = a + b = " << c;
cout << "a + b - c = " << a + b - c;
cout << "a + b - (b + a) = " << a + b - (b + a) << "\n";
 
cout << "a + a + a + a + a - 5 * a = " << a + a + a + a + a - 5 * a;
cout << "a * 12345 = " << a * 12345;
cout << "a * -12345 = " << a * -12345;
cout << "a * 12345 + a * -12345 = " << a * 12345 + a * -12345;
cout << "a * 12345 - (a * 12000 + a * 345) = " << a * 12345 - (a * 12000 + a * 345);
cout << "a * 12345 - (a * 12001 + a * 345) = " << a * 12345 - (a * 12000 + a * 344) << "\n";
 
const EllipticPoint zero;
EllipticPoint g;
cout << "g = zero = " << g;
cout << "g += a = " << (g+=a);
cout << "g += zero = " << (g+=zero);
cout << "g += b = " << (g+=b);
cout << "b + b - b * 2 = " << (b + b - b * 2) << "\n";
 
EllipticPoint special(0); // the point where the curve crosses the x-axis
cout << "special = " << special; // this has the minimum possible value for x
cout << "special *= 2 = " << (special*=2); // doubling it gives zero
return 0;
}</syntaxhighlight>
 
{{out}}
<pre>
a = (-1.81712, 1)
b = (-1.44225, 2)
c = a + b = (10.3754, -33.5245)
a + b - c = (Zero)
a + b - (b + a) = (Zero)
 
a + a + a + a + a - 5 * a = (Zero)
a * 12345 = (10.7586, 35.3874)
a * -12345 = (10.7586, -35.3874)
a * 12345 + a * -12345 = (Zero)
a * 12345 - (a * 12000 + a * 345) = (Zero)
a * 12345 - (a * 12001 + a * 345) = (-1.81712, 1)
 
g = zero = (Zero)
g += a = (-1.81712, 1)
g += zero = (-1.81712, 1)
g += b = (10.3754, -33.5245)
b + b - b * 2 = (Zero)
 
special = (-1.91293, 0)
special *= 2 = (Zero)
</pre>
 
=={{header|D}}==
{{trans|Go}}
<langsyntaxhighlight lang="d">import std.stdio, std.math, std.string;
 
enum bCoeff = 7;
Line 197 ⟶ 532:
writeln("a + b + d = ", a + b + d);
writeln("a * 12345 = ", a * 12345);
}</langsyntaxhighlight>
{{out}}
<pre>a = (-1.817, 1.000)
Line 209 ⟶ 544:
=={{header|EchoLisp}}==
===Arithmetic===
<langsyntaxhighlight lang="scheme">
(require 'struct)
(decimals 4)
Line 273 ⟶ 608:
(printf "%d additions a+(a+(a+...))) → %a" n e)
(printf "multiplication a x %d → %a" n (E-mul a n)))
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 296 ⟶ 631:
===Plotting===
;; Result at http://www.echolalie.org/echolisp/help.html#plot-xy
<langsyntaxhighlight lang="scheme">
(define (E-plot (r 3))
(define (Ellie x y) (- (* y y) (* x x x) 7))
Line 313 ⟶ 648:
(plot-segment R.x R.y R.x (- R.y))
)
</syntaxhighlight>
</lang>
 
=={{header|Go}}==
{{trans|C}}
<langsyntaxhighlight lang="go">package main
 
import (
Line 409 ⟶ 744:
show("a + b + d = ", add(a, add(b, d)))
show("a * 12345 = ", mul(a, 12345))
}</langsyntaxhighlight>
{{out}}
<pre>a = (-1.817, 1.000)
Line 419 ⟶ 754:
a * 12345 = (10.759, 35.387)</pre>
 
=={{header|JHaskell}}==
First, some useful imports:
Follows the C contribution.
<syntaxhighlight lang="haskell">import Data.Monoid
import Control.Monad (guard)
import Test.QuickCheck (quickCheck)</syntaxhighlight>
 
The datatype for a point on an elliptic curve:
<lang j>C=. 7
 
<syntaxhighlight lang="haskell">import Data.Monoid
zero=: _j_
 
data Elliptic = Elliptic Double Double | Zero
isZero=: 1e20 < |@{.@+.
deriving Show
 
instance Eq Elliptic where
neg=: 1 _1&*&.+.
p == q = dist p q < 1e-14
where
dist Zero Zero = 0
dist Zero p = 1/0
dist p Zero = 1/0
dist (Elliptic x1 y1) (Elliptic x2 y2) = (x2-x1)^2 + (y2-y1)^2
 
inv Zero = Zero
dbl=: 3 :0
inv (Elliptic x y) = Elliptic x (-y)</syntaxhighlight>
if. isZero y do. y return. end.
'px py'=. +. y
r j. py-~L*px-r=. (2*px)-~*~L=. (3*px*px)% 2*py
)
 
Points on elliptic curve form a monoid:
add=: 4 :0
<syntaxhighlight lang="haskell">instance Monoid Elliptic where
if. x=y do. dbl x return. end.
mempty = Zero
if. isZero x do. y return. end.
if. isZero y do. x return. end.
'px py'=. +. x
'qx qy'=. +. y
r j. py-~ L * px-r=. (px+qx)-~*~L=. (qy-py)%qx-px
)
 
mappend Zero p = p
mul=: [:{.[:;[:(,dbl)/@]`((add,dbl@])/@])@.[&.>/([:<"0 #:@]),[:< zero,[
mappend p Zero = p
mappend p@(Elliptic x1 y1) q@(Elliptic x2 y2)
| p == inv q = Zero
| p == q = mkElliptic $ 3*x1^2/(2*y1)
| otherwise = mkElliptic $ (y2 - y1)/(x2 - x1)
where
mkElliptic l = let x = l^2 - x1 - x2
y = l*(x1 - x) - y1
in Elliptic x y</syntaxhighlight>
 
Examples given in other solutions:
from=: j.~[:(**3&%:@|)C-~*~
 
<syntaxhighlight lang="haskell">ellipticX b y = Elliptic (qroot (y^2 - b)) y
show =: (,('( ',[,' , ',' )',~])&":/@+.@])`('Zero',~[)@.(isZero@])
where qroot x = signum x * abs x ** (1/3)</syntaxhighlight>
 
<pre>λ> let a = ellipticX 7 1
λ> let b = ellipticX 7 2
λ> a
Elliptic (-1.8171205928321397) 1.0
λ> b
Elliptic (-1.4422495703074083) 2.0
λ> let c = a <> b
λ> c
Elliptic 10.375375389201409 (-33.524509096269696)
λ> let d = inv c
λ> c <> d
Zero
λ> a <> b <> d
Zero</pre>
 
Extra credit: multiplication.
task=: 3 :0
a=. from 1
b=. from 2
 
1. direct monoidal solution:
smoutput 'a = ' show a
<syntaxhighlight lang="haskell">mult :: Int -> Elliptic -> Elliptic
smoutput 'b = ' show b
mult n = mconcat . replicate n</syntaxhighlight>
smoutput 'c = a + b = ' show c =. a add b
 
smoutput 'd = -c = ' show d =. neg c
2. efficient recursive solution:
smoutput 'c + d = ' show c add d
<syntaxhighlight lang="haskell">n `mult` p
smoutput 'a + b + d = ' show add/ a, b, d
| n == 0 = Zero
smoutput 'a * 12345 = ' show a mul 12345
| n == 1 = p
)</lang>
| n == 2 = p <> p
| n < 0 = inv ((-n) `mult` p)
| even n = 2 `mult` ((n `div` 2) `mult` p)
| odd n = p <> (n -1) `mult` p</syntaxhighlight>
 
<pre>λ> 12345 `mult` a
Elliptic 10.758570529320476 35.387434774280486</pre>
 
===Testing===
 
We use QuickCheck to test general properties of points on arbitrary elliptic curve.
 
<syntaxhighlight lang="haskell">-- for given a, b and x returns a point on the positive branch of elliptic curve (if point exists)
elliptic a b Nothing = Just Zero
elliptic a b (Just x) =
do let y2 = x**3 + a*x + b
guard (y2 > 0)
return $ Elliptic x (sqrt y2)
 
addition a b x1 x2 =
let p = elliptic a b
s = p x1 <> p x2
in (s /= Nothing) ==> (s <> (inv <$> s) == Just Zero)
 
associativity a b x1 x2 x3 =
let p = elliptic a b
in (p x1 <> p x2) <> p x3 == p x1 <> (p x2 <> p x3)
 
commutativity a b x1 x2 =
let p = elliptic a b
in p x1 <> p x2 == p x2 <> p x1</syntaxhighlight>
 
<pre>λ> quickCheck addition
+++ OK, passed 100 tests.
λ> quickCheck associativity
+++ OK, passed 100 tests.
λ> quickCheck commutativity
+++ OK, passed 100 tests.</pre>
 
=={{header|J}}==
Follows the C contribution.
 
<syntaxhighlight lang="j">zero=: _j_
isZero=: 1e20 < |@{.@+.
neg=: +
dbl=: monad define
'p_x p_y'=. +. p=. y
if. isZero p do. p return. end.
L=. 1.5 * p_x*p_x % p_y
r=. (L*L) - 2*p_x
r j. (L * p_x-r) - p_y
)
add=: dyad define
'p_x p_y'=. +. p=. x
'q_x q_y'=. +. q=. y
if. x=y do. dbl x return. end.
if. isZero x do. y return. end.
if. isZero y do. x return. end.
L=. %~/ +. q-p
r=. (L*L) - p_x + q_x
r j. (L * p_x-r) - p_y
)
 
mul=: dyad define
a=. zero
for_bit.|.#:y do.
if. bit do.
a=. a add x
end.
x=. dbl x
end.
a
)
 
NB. C is 7
from=: j.~ [:(* * 3 |@%: ]) _7 0 1 p. ]
show=: monad define
if. isZero y do. 'Zero' else.
'a b'=. ":each +.y
'(',a,', ', b,')'
end.
)
 
task=: 3 :0
a=. from 1
b=. from 2
echo 'a = ', show a
echo 'b = ', show b
echo 'c = a + b = ', show c =. a add b
echo 'd = -c = ', show d =. neg c
echo 'c + d = ', show c add d
echo 'a + b + d = ', show add/ a, b, d
echo 'a * 12345 = ', show a mul 12345
)</syntaxhighlight>
{{out}}
<langsyntaxhighlight lang="j"> task 'uit'
a = ( _1.81712 , 1 )
b = ( _1.44225 , 2 )
c = a + b = ( 10.3754 , _33.5245 )
d = -c = ( 10.3754 , 33.5245 )
c + d = Zero
a + b + d = Zero
a * 12345 = ( 10.7586 , 35.3875 3874)</langsyntaxhighlight>
 
=={{header|Java}}==
{{trans|D}}
<langsyntaxhighlight lang="java">import static java.lang.Math.*;
import java.util.Locale;
 
Line 562 ⟶ 1,021:
return String.format(Locale.US, "(%.3f,%.3f)", this.x, this.y);
}
}</langsyntaxhighlight>
<pre>a = (-1.817,1.000)
b = (-1.442,2.000)
Line 570 ⟶ 1,029:
a + b + d = Zero
a * 12345 = (10.759,35.387)</pre>
 
=={{header|jq}}==
'''Adapted from [[#Wren|Wren]]'''
{{works with|jq}}
''Also works with gojq and fq''
 
'''Preliminaries'''
<syntaxhighlight lang=jq>
def round($ndec): pow(10;$ndec) as $p | . * $p | round / $p;
 
def idiv2: (. - (. % 2)) / 2;
 
def bitwise:
recurse( if . >= 2 then idiv2 else empty end) | . % 2;
 
def bitwise_and_nonzero($x; $y):
[$x|bitwise] as $x
| [$y|bitwise] as $y
| ([$x, $y] | map(length) | min) as $min
| any(range(0; $min) ; $x[.] == 1 and $y[.] == 1);
</syntaxhighlight>
'''Elliptic Curve Arithmetic'''
<syntaxhighlight lang=jq>
def Pt(x;y): [x, y];
 
def isPt: type == "array" and length == 2 and (map(type)|unique) == ["number"];
 
def zero: Pt(infinite; infinite);
 
def isZero: .[0] | (isinfinite or . == 0);
 
def C: 7;
 
def fromNum: Pt((.*. - C)|cbrt; .) ;
 
def double:
if isZero then .
else . as [$x,$y]
| ((3 * ($x * $x)) / (2 * .[1])) as $l
| ($l*$l - 2*$x) as $t
| Pt($t; $l*($x - $t) - $y)
end;
 
def minus: .[1] *= -1;
 
def plus($other):
if ($other|isPt|not) then "Argument of plus(Pt) must be a Pt object but got \(.)." | error
elif (.[0] == $other[0] and .[1] == $other[1]) then double
elif isZero then $other
elif ($other|isZero) then .
else . as [$x, $y]
| (if $other[0] == $x then infinite
else (($other[1] - $y) / ($other[0] - $x)) end) as $l
| ($l*$l - $x - $other[0]) as $t
| Pt($t; $l*($x-$t) - $y)
end;
 
def plus($a; $b): $a | plus($b);
 
def mult($n):
if ($n|type) != "number" or ($n | ( . != floor))
then "Argument must be an integer, not \($n)." | error
else { r: zero,
p: .,
i: 1 }
| until (.i > $n;
if bitwise_and_nonzero(.i; $n) then .r = plus(.r;.p) else . end
| .p |= double
| .i *= 2 )
| .r
end;
 
def toString:
if isZero then "Zero"
else map(round(3))
end;
 
 
def a: 1|fromNum;
def b: 2|fromNum;
def c: plus(a; b);
def d: c | minus;
 
def task:
"a = \(a|toString)",
"b = \(b|toString)",
"c = a + b = \(c|toString)",
"d = -c = \(d|toString)",
"c + d = \(plus(c; d)|toString)",
"(a+b) + d = \(plus(plus(a; b);d)|toString)",
"a * 12345 = \(a | mult(12345) | toString)"
;
 
task
</syntaxhighlight>
{{output}}
<pre>
a = [-1.817,1]
b = [-1.442,2]
c = a + b = [10.375,-33.525]
d = -c = [10.375,33.525]
c + d = Zero
(a+b) + d = Zero
a * 12345 = [10.759,35.387]
</pre>
 
=={{header|Julia}}==
{{works with|Julia|0.6}}
{{trans|Python}}
 
<syntaxhighlight lang="julia">struct Point{T<:AbstractFloat}
x::T
y::T
end
Point{T}() where T<:AbstractFloat = Point{T}(Inf, Inf)
Point() = Point{Float64}()
 
Base.show(io::IO, p::Point{T}) where T = iszero(p) ? print(io, "Zero{$T}") : @printf(io, "{%s}(%.3f, %.3f)", T, p.x, p.y)
Base.copy(p::Point) = Point(p.x, p.y)
Base.iszero(p::Point{T}) where T = p.x in (-Inf, Inf)
Base.:-(p::Point) = Point(p.x, -p.y)
 
function dbl(p::Point{T}) where T
iszero(p) && return p
 
L = 3p.x ^ 2 / 2p.y
x = L ^ 2 - 2p.x
y = L * (p.x - x) - p.y
return Point{T}(x, y)
end
Base.:(==)(a::Point{T}, C::Point{T}) where T = a.x == C.x && a.y == C.y
 
function Base.:+(p::Point{T}, q::Point{T}) where T
p == q && return dbl(p)
iszero(p) && return q
iszero(q) && return p
 
L = (q.y - p.y) / (q.x - p.x)
x = L ^ 2 - p.x - q.x
y = L * (p.x - x) - p.y
return Point{T}(x, y)
end
function Base.:*(p::Point, n::Integer)
r = Point()
i = 1
while i ≤ n
if i & n != 0 r += p end
p = dbl(p)
i <<= 1
end
return r
end
Base.:*(n::Integer, p::Point) = p * n
 
const C = 7
function Point(y::AbstractFloat)
n = y ^ 2 - C
x = n ≥ 0 ? n ^ (1 / 3) : -((-n) ^ (1 / 3))
return Point{typeof(y)}(x, y)
end
 
a = Point(1.0)
b = Point(2.0)
@show a b
@show c = a + b
@show d = -c
@show c + d
@show a + b + d
@show 12345a</syntaxhighlight>
 
{{out}}
<pre>a = {Float64}(-1.817, 1.000)
b = {Float64}(-1.442, 2.000)
c = a + b = {Float64}(10.375, -33.525)
d = -c = {Float64}(10.375, 33.525)
c + d = Zero{Float64}
a + b + d = Zero{Float64}
12345a = {Float64}(10.759, 35.387)</pre>
 
===Julia 1.x compatible version===
Adds assertion checks for points to be on the curve.
<syntaxhighlight lang="julia">
using Printf
import Base.in
 
struct EllipticCurve{T <: AbstractFloat}
a::T
b::T
EllipticCurve(a::T, b::T) where T <: AbstractFloat = new{T}(a, b)
end
 
in(c::EllipticCurve, x, y) = (x == Inf || y == Inf || y^2 ≈ x^3 + c.a * x + c.b)
 
const Curve07 = EllipticCurve(0.0, 7.0)
 
struct EPoint{T <: AbstractFloat}
x::T
y::T
curve::EllipticCurve
end
EPoint{T}() where T <: AbstractFloat = EPoint{T}(Inf, Inf, Curve07)
EPoint() = EPoint{Float64}()
function EPoint(x, y, c::EllipticCurve=Curve07)
@assert in(c, x, y)
EPoint(x, y, c)
end
 
Base.show(io::IO, p::EPoint{T}) where T = iszero(p) ? print(io, "Zero{$T}") : @printf(io, "{%s}(%.3f, %.3f)", T, p.x, p.y)
Base.copy(p::EPoint) = EPoint(p.x, p.y, p.curve)
Base.iszero(p::EPoint{T}) where T = p.x in (-Inf, Inf, p.curve)
Base.:-(p::EPoint) = EPoint(p.x, -p.y, p.curve)
 
function dbl(p::EPoint{T}) where T
iszero(p) && return p
 
L = 3p.x ^ 2 / 2p.y
x = L ^ 2 - 2p.x
y = L * (p.x - x) - p.y
return EPoint{T}(x, y, p.curve)
end
 
function Base.:(==)(a::EPoint{T}, C::EPoint{T}) where T
@assert a.curve == C.curve
return (iszero(a) && iszero(C)) || (a.x == C.x && a.y == C.y)
end
 
function Base.:+(p::EPoint{T}, q::EPoint{T}) where T
@assert p.curve == q.curve
p == q && return dbl(p)
iszero(p) && return q
iszero(q) && return p
 
L = (q.y - p.y) / (q.x - p.x)
x = L ^ 2 - p.x - q.x
y = L * (p.x - x) - p.y
return EPoint{T}(x, y, p.curve)
end
 
function Base.:*(p::EPoint, n::Integer)
r = EPoint()
i = 1
while i ≤ n
if i & n != 0 r += p end
p = dbl(p)
i <<= 1
end
return r
end
Base.:*(n::Integer, p::EPoint) = p * n
 
const C = 7.0
 
function EPoint(y::AbstractFloat)
n = y ^ 2 - C
x = n ≥ 0 ? n ^ (1 / 3) : -((-n) ^ (1 / 3))
return EPoint{typeof(y)}(x, y, Curve07)
end
 
a = EPoint(1.0)
b = EPoint(2.0)
@show a b
@show c = a + b
@show d = -c
@show c + d
@show a + b + d
@show 12345a
</syntaxhighlight>
Output: Same as the original, Julia 0.6 version code.
 
=={{header|Kotlin}}==
{{trans|C}}
<syntaxhighlight lang="scala">// version 1.1.4
 
const val C = 7
 
class Pt(val x: Double, val y: Double) {
val zero get() = Pt(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY)
 
val isZero get() = x > 1e20 || x < -1e20
 
fun dbl(): Pt {
if (isZero) return this
val l = 3.0 * x * x / (2.0 * y)
val t = l * l - 2.0 * x
return Pt(t, l * (x - t) - y)
}
 
operator fun unaryMinus() = Pt(x, -y)
 
operator fun plus(other: Pt): Pt {
if (x == other.x && y == other.y) return dbl()
if (isZero) return other
if (other.isZero) return this
val l = (other.y - y) / (other.x - x)
val t = l * l - x - other.x
return Pt(t, l * (x - t) - y)
}
 
operator fun times(n: Int): Pt {
var r: Pt = zero
var p = this
var i = 1
while (i <= n) {
if ((i and n) != 0) r += p
p = p.dbl()
i = i shl 1
}
return r
}
 
override fun toString() =
if (isZero) "Zero" else "(${"%.3f".format(x)}, ${"%.3f".format(y)})"
}
 
fun Double.toPt() = Pt(Math.cbrt(this * this - C), this)
 
fun main(args: Array<String>) {
val a = 1.0.toPt()
val b = 2.0.toPt()
val c = a + b
val d = -c
println("a = $a")
println("b = $b")
println("c = a + b = $c")
println("d = -c = $d")
println("c + d = ${c + d}")
println("a + b + d = ${a + b + d}")
println("a * 12345 = ${a * 12345}")
}</syntaxhighlight>
 
{{out}}
<pre>
a = (-1.817, 1.000)
b = (-1.442, 2.000)
c = a + b = (10.375, -33.525)
d = -c = (10.375, 33.525)
c + d = Zero
a + b + d = Zero
a * 12345 = (10.759, 35.387)
</pre>
 
=={{header|Nim}}==
{{trans|C}}
<syntaxhighlight lang="nim">import math, strformat
 
const B = 7
 
type Point = tuple[x, y: float]
 
#---------------------------------------------------------------------------------------------------
 
template zero(): Point =
(Inf, Inf)
 
#---------------------------------------------------------------------------------------------------
 
func isZero(pt: Point): bool {.inline.} =
pt.x > 1e20 or pt.x < -1e20
 
#---------------------------------------------------------------------------------------------------
 
func `-`(pt: Point): Point {.inline.} =
(pt.x, -pt.y)
 
#---------------------------------------------------------------------------------------------------
 
func double(pt: Point): Point =
 
if pt.isZero: return pt
 
let t = (3 * pt.x * pt.x) / (2 * pt.y)
result.x = t * t - 2 * pt.x
result.y = t * (pt.x - result.x) - pt.y
 
#---------------------------------------------------------------------------------------------------
 
func `+`(pt1, pt2: Point): Point =
 
if pt1.x == pt2.x and pt1.y == pt2.y: return double(pt1)
if pt1.isZero: return pt2
if pt2.isZero: return pt1
 
let t = (pt2.y - pt1.y) / (pt2.x - pt1.x)
result.x = t * t - pt1.x - pt2.x
result.y = t * (pt1.x - result.x) - pt1.y
 
#---------------------------------------------------------------------------------------------------
 
func `*`(pt: Point; n: int): Point =
 
result = zero()
var pt = pt
var i = 1
 
while i <= n:
if (i and n) != 0:
result = result + pt
pt = double(pt)
i = i shl 1
 
#---------------------------------------------------------------------------------------------------
 
func `$`(pt: Point): string =
if pt.isZero: "Zero" else: fmt"({pt.x:.3f}, {pt.y:.3f})"
 
#---------------------------------------------------------------------------------------------------
 
func fromY(y: float): Point {.inline.} =
(cbrt(y * y - B), y)
 
#———————————————————————————————————————————————————————————————————————————————————————————————————
 
when isMainModule:
let a = fromY(1)
let b = fromY(2)
 
echo "a = ", a
echo "b = ", b
let c = a + b
echo "c = a + b = ", c
let d = -c
echo "d = -c = ", d
echo "c + d = ", c + d
echo "a + b + d = ", a + b + d
echo "a * 12345 = ", a * 12345</syntaxhighlight>
 
{{out}}
<pre>a = (-1.817, 1.000)
b = (-1.442, 2.000)
c = a + b = (10.375, -33.525)
d = -c = (10.375, 33.525)
c + d = Zero
a + b + d = Zero
a * 12345 = (10.759, 35.388)</pre>
 
=={{header|OCaml}}==
Original version by [http://rosettacode.org/wiki/User:Vanyamil User:Vanyamil].
Some float-precision issues but overall works.
<syntaxhighlight lang="ocaml">
(* Task : Elliptic_curve_arithmetic *)
 
(*
Using the secp256k1 elliptic curve (a=0, b=7),
define the addition operation on points on the curve.
Extra credit: define the full elliptic curve arithmetic
(still not modular, though) by defining a "multiply" function.
*)
 
(*** Helpers ***)
 
type ec_point = Point of float * float | Inf
 
type ec_curve = { a : float; b : float }
 
(* By default, cube root doesn't work for negative bases *)
let cube_root : float -> float =
let third = 1. /. 3. in
let f x =
if x > 0.
then x ** third
else ~-. (~-. x ** third)
in
f
 
(* Finds the left-most x on this curve *)
let ec_minx ({a; b} : ec_curve) : float =
let factor = ~-. b *. 0.5 in
let discr = (factor ** 2.) +. (a ** 3. /. 27.) in
if discr <= 0.
then failwith "Not a simple curve"
else
let root = sqrt discr in
cube_root (factor +. root) +. cube_root (factor -. root)
 
(* Negates the point by negating y coord *)
let ec_neg : ec_point -> ec_point = function
| Inf -> Inf
| Point (x, y) -> Point (x, ~-. y)
 
(*** Actual task at hand ***)
 
(* Generates a random point in the vicinity of x=0 *)
let ec_random ({a; b} as c : ec_curve) : ec_point =
let minx = ec_minx c in
let x = Random.float (~-. minx *. 2.) +. minx in
let rhs = x ** 3. +. a *. x +. b in
Point (x, sqrt rhs)
 
(* Verifies that the point is on curve.
Due to rounding errors, sometimes these calculations aren't perfect.
*)
let on_curve ?(debug : bool = false) ({a; b} : ec_curve) : ec_point -> bool = function
| Inf -> true
| Point (x, y) ->
let lhs = y *. y in
let rhs = x ** 3. +. a *. x +. b in
let delta = abs_float (lhs -. rhs) in
(
if debug then Printf.printf "Delta = %.8f" delta;
delta < 0.000001
)
 
(* Doubles a point on the curve (adds a point to itself) *)
let ec_double ({a; b} as c : ec_curve) : ec_point -> ec_point = function
| Inf -> Inf
| Point (x, y) as p ->
if not (on_curve c p)
then failwith "Point not on this curve."
else if y = 0.
then Inf
else
let s = (3. *. x *. x +. a) /. (2. *. y) in
let x' = s *. s -. 2. *. x in
let y' = y +. s *. (x' -. x) in
Point (x', -. y')
 
(* Adds any two points on the curve *)
let ec_add ({a; b} as c : ec_curve) (p : ec_point) (q : ec_point) : ec_point =
match p, q with
| Inf, x | x, Inf -> x
| Point (px, py), Point (qx, qy) ->
if not (on_curve c p) || not (on_curve c q)
then failwith "Point not on this curve."
else if abs_float (px -. qx) < 0.000001 then
begin
if abs_float (py +. qy) < 0.000001
then Inf
else
(* py must equal qy here, otherwise something goes real bad *)
ec_double c p |> ec_neg
end
else
let s = (py -. qy) /. (px -. qx) in
let rx = s *. s -. px -. qx in
let ry = py +. s *. (rx -. px) in
Point (rx, -. ry)
 
(* Extra credit : multiplies a point by a scalar *)
let ec_mul ({a; b} as c : ec_curve) (p : ec_point) (n : int) : ec_point =
let rec helper n curPow acc =
if n = 0 then acc
else
let doubled = ec_double c curPow in
if n mod 2 = 0
then helper (n / 2) doubled acc
else helper (n / 2) doubled (ec_add c acc curPow)
in
helper n p Inf
 
(*** Output ***)
 
let string_of_point : ec_point -> string = function
| Inf -> "Zero"
| Point (x, y) -> Printf.sprintf "(%.4f, %.4f)" x y
 
let print_output () =
let c = { a = 0.; b = 7. } in
let p = ec_random c in
let q = ec_random c in
let r = ec_add c p q in
let t = ec_neg r in
Printf.printf "p = %s\n" (string_of_point p);
Printf.printf "q = %s\n" (string_of_point q);
Printf.printf "r = p + q = %s\n" (string_of_point r);
Printf.printf "t = -r = %s\n" (string_of_point t);
Printf.printf "r + t = %s\n" (ec_add c r t |> string_of_point);
Printf.printf "p + (q + t) = %s\n" (ec_add c q t |> ec_add c p |> string_of_point);
Printf.printf "p * 12345 = %s\n" (ec_mul c p 12345 |> string_of_point)
 
let _ =
print_output ();
print_output ()
</syntaxhighlight>
{{out}}
<pre>
p = (-0.0489, 2.6457)
q = (-0.0236, 2.6457)
r = p + q = (0.0726, -2.6458)
t = -r = (0.0726, 2.6458)
r + t = Zero
p + (q + t) = Zero
p * 12345 = (-1.7905, -1.1224)
 
p = (1.2715, 3.0092)
q = (1.6370, 3.3745)
r = p + q = (-1.9103, 0.1696)
t = -r = (-1.9103, -0.1696)
r + t = Zero
p + (q + t) = Zero
p * 12345 = (-0.3948, -2.6341)
</pre>
 
=={{header|PARI/GP}}==
The examples were borrowed from C, though the coding is built-in for GP and so not ported.
<langsyntaxhighlight lang="parigp">e=ellinit([0,7]);
a=[-6^(1/3),1]
b=[-3^(1/3),2]
Line 580 ⟶ 1,630:
elladd(e,c,d)
elladd(e,elladd(e,a,b),d)
ellmul(e,a,12345)</langsyntaxhighlight>
{{output}}
<pre>%1 = [-1.8171205928321396588912117563272605024, 1]
Line 592 ⟶ 1,642:
=={{header|Perl}}==
{{trans|C}}
<langsyntaxhighlight lang="perl">package EC;
our ($a, $b) = (0, 7);
{
our ($A, $B) = (0, 7);
package EC::Point;
sub new { my $class = shift; bless [ @_ ], $class }
Line 626 ⟶ 1,676:
 
package Test;
my $ap = +EC::Point->new(-($EC::bB - 1)**(1/3), 1);
my $bq = +EC::Point->new(-($EC::bB - 4)**(1/3), 2);
print my $cs = $ap + $bq, "\n";
print "$_\n" for $ap, $bq, $cs;
print "check alignementalignment... ";
print abs(($bq->x - $ap->x)*(-$cs->y - $ap->y) - ($bq->y - $ap->y)*($cs->x - $ap->x)) < 0.001
? "ok" : "wrong";</syntaxhighlight>
</lang>
{{out}}
<pre>EC-point at x=-1.817121, y=1.000000
EC-point at x=-1.442250, y=2.000000
EC-point at x=10.375375, y=-33.524509
check alignementalignment... ok
</pre>
 
=={{header|Perl 6Phix}}==
{{Trans|C}}
<lang perl6>unit module EC;
<!--<syntaxhighlight lang="phix">(phixonline)-->
our ($A, $B) = (0, 7);
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">X</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">Y</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">bCoeff</span><span style="color: #0000FF;">=</span><span style="color: #000000;">7</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">INF</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1e300</span><span style="color: #0000FF;">*</span><span style="color: #000000;">1e300</span>
<span style="color: #008080;">type</span> <span style="color: #000000;">point</span><span style="color: #0000FF;">(</span><span style="color: #004080;">object</span> <span style="color: #000000;">pt</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #004080;">sequence</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pt</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">and</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pt</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">2</span> <span style="color: #008080;">and</span> <span style="color: #004080;">atom</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pt</span><span style="color: #0000FF;">[</span><span style="color: #000000;">X</span><span style="color: #0000FF;">])</span> <span style="color: #008080;">and</span> <span style="color: #004080;">atom</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pt</span><span style="color: #0000FF;">[</span><span style="color: #000000;">Y</span><span style="color: #0000FF;">])</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">type</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">zero</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">point</span> <span style="color: #000000;">pt</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">INF</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">INF</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">pt</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">is_zero</span><span style="color: #0000FF;">(</span><span style="color: #000000;">point</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">[</span><span style="color: #000000;">X</span><span style="color: #0000FF;">]></span><span style="color: #000000;">1e20</span> <span style="color: #008080;">or</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">[</span><span style="color: #000000;">X</span><span style="color: #0000FF;">]<-</span><span style="color: #000000;">1e20</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">neg</span><span style="color: #0000FF;">(</span><span style="color: #000000;">point</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">p</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">p</span><span style="color: #0000FF;">[</span><span style="color: #000000;">X</span><span style="color: #0000FF;">],</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">p</span><span style="color: #0000FF;">[</span><span style="color: #000000;">Y</span><span style="color: #0000FF;">]}</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">p</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">dbl</span><span style="color: #0000FF;">(</span><span style="color: #000000;">point</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">point</span> <span style="color: #000000;">r</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">p</span>
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #000000;">is_zero</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">L</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">3</span><span style="color: #0000FF;">*</span><span style="color: #000000;">p</span><span style="color: #0000FF;">[</span><span style="color: #000000;">X</span><span style="color: #0000FF;">]*</span><span style="color: #000000;">p</span><span style="color: #0000FF;">[</span><span style="color: #000000;">X</span><span style="color: #0000FF;">])/(</span><span style="color: #000000;">2</span><span style="color: #0000FF;">*</span><span style="color: #000000;">p</span><span style="color: #0000FF;">[</span><span style="color: #000000;">Y</span><span style="color: #0000FF;">])</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">x</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">L</span><span style="color: #0000FF;">*</span><span style="color: #000000;">L</span><span style="color: #0000FF;">-</span><span style="color: #000000;">2</span><span style="color: #0000FF;">*</span><span style="color: #000000;">p</span><span style="color: #0000FF;">[</span><span style="color: #000000;">X</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">r</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">L</span><span style="color: #0000FF;">*(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">[</span><span style="color: #000000;">X</span><span style="color: #0000FF;">]-</span><span style="color: #000000;">x</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">p</span><span style="color: #0000FF;">[</span><span style="color: #000000;">Y</span><span style="color: #0000FF;">]}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">r</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">add</span><span style="color: #0000FF;">(</span><span style="color: #000000;">point</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">point</span> <span style="color: #000000;">q</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">==</span><span style="color: #000000;">q</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">dbl</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">is_zero</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">q</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">is_zero</span><span style="color: #0000FF;">(</span><span style="color: #000000;">q</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">p</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">L</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">q</span><span style="color: #0000FF;">[</span><span style="color: #000000;">Y</span><span style="color: #0000FF;">]-</span><span style="color: #000000;">p</span><span style="color: #0000FF;">[</span><span style="color: #000000;">Y</span><span style="color: #0000FF;">])/(</span><span style="color: #000000;">q</span><span style="color: #0000FF;">[</span><span style="color: #000000;">X</span><span style="color: #0000FF;">]-</span><span style="color: #000000;">p</span><span style="color: #0000FF;">[</span><span style="color: #000000;">X</span><span style="color: #0000FF;">])</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">x</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">L</span><span style="color: #0000FF;">*</span><span style="color: #000000;">L</span><span style="color: #0000FF;">-</span><span style="color: #000000;">p</span><span style="color: #0000FF;">[</span><span style="color: #000000;">X</span><span style="color: #0000FF;">]-</span><span style="color: #000000;">q</span><span style="color: #0000FF;">[</span><span style="color: #000000;">X</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">point</span> <span style="color: #000000;">r</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">L</span><span style="color: #0000FF;">*(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">[</span><span style="color: #000000;">X</span><span style="color: #0000FF;">]-</span><span style="color: #000000;">x</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">p</span><span style="color: #0000FF;">[</span><span style="color: #000000;">Y</span><span style="color: #0000FF;">]}</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">r</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">mul</span><span style="color: #0000FF;">(</span><span style="color: #000000;">point</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">point</span> <span style="color: #000000;">r</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">zero</span><span style="color: #0000FF;">()</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">i</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">i</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">n</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">and_bits</span><span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #000000;">r</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">add</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">p</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">dbl</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">i</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">*</span><span style="color: #000000;">2</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">r</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">show</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">point</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">&</span><span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">is_zero</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">)?</span><span style="color: #008000;">"Zero\n"</span><span style="color: #0000FF;">:</span><span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"(%.3f, %.3f)\n"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">)))</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">cbrt</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">c</span><span style="color: #0000FF;">>=</span><span style="color: #000000;">0</span><span style="color: #0000FF;">?</span><span style="color: #7060A8;">power</span><span style="color: #0000FF;">(</span><span style="color: #000000;">c</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">/</span><span style="color: #000000;">3</span><span style="color: #0000FF;">):-</span><span style="color: #7060A8;">power</span><span style="color: #0000FF;">(-</span><span style="color: #000000;">c</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">/</span><span style="color: #000000;">3</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">from_y</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">point</span> <span style="color: #000000;">r</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">cbrt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">y</span><span style="color: #0000FF;">*</span><span style="color: #000000;">y</span><span style="color: #0000FF;">-</span><span style="color: #000000;">bCoeff</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">r</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #000000;">point</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">d</span>
<span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">from_y</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">b</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">from_y</span><span style="color: #0000FF;">(</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">add</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">d</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">neg</span><span style="color: #0000FF;">(</span><span style="color: #000000;">c</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">show</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"a = "</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">show</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"b = "</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">show</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"c = a + b = "</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">show</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"d = -c = "</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">d</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">show</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"c + d = "</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">add</span><span style="color: #0000FF;">(</span><span style="color: #000000;">c</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">d</span><span style="color: #0000FF;">))</span>
<span style="color: #000000;">show</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"a + b + d = "</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">add</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">add</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">d</span><span style="color: #0000FF;">)))</span>
<span style="color: #000000;">show</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"a * 12345 = "</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">mul</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">12345</span><span style="color: #0000FF;">))</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
a = (-1.817, 1.000)
b = (-1.442, 2.000)
c = a + b = (10.375, -33.525)
d = -c = (10.375, 33.525)
c + d = Zero
a + b + d = Zero
a * 12345 = (10.759, 35.387)
</pre>
 
=={{header|PicoLisp}}==
role Horizon { method gist { 'EC Point at horizon' } }
<syntaxhighlight lang="picolisp">(scl 16)
class Point {
(load "@lib/math.l")
has ($.x, $.y);
(setq *B 7)
multi method new(
(de from_y (Y)
$x, $y where $y**2 ~~ $x**3 + $A*$x + $B
(let
) { self.bless(:$x, :$y) }
(A (* 1.0 (- (* Y Y) *B))
multi method new(Horizon $) { self.bless but Horizon }
method gist { "EC Point atB x=$(pow (abs A) (*/ 1.0 1.x,0 y=$3.y"0)) })
(list
}
(if (gt0 A) B (- B))
 
(* Y 1.0) ) ) )
multi prefix:<->(Point $p) { Point.new: x => $p.x, y => -$p.y }
(de prn (P)
multi prefix:<->(Horizon $) { Horizon }
(if (is_zero P)
multi infix:<->(Point $a, Point $b) { $a + -$b }
"Zero"
 
(pack
multi infix:<+>(Horizon $, Point $p) { $p }
(round (car P) 3)
multi infix:<+>(Point $p, Horizon) { $p }
" "
 
(round (cadr P) 3) ) ) )
multi infix:<*>(Point $u, Int $n) { $n * $u }
(de neg (P)
multi infix:<*>(Int $n, Horizon) { Horizon }
(list (car P) (*/ -1.0 (cadr P) 1.0)) )
multi infix:<*>(0, Point) { Horizon }
(de is_zero (P)
multi infix:<*>(1, Point $p) { $p }
(or
multi infix:<*>(2, Point $p) {
my $l (=T (3*$p.x**2car + $AP) / (2 *$p.y);
(=T (cadr P))
my $y = $l*($p.x - my $x = $l**2 - 2*$p.x) - $p.y;
(> (length (car P)) 20) ) )
$p.bless(:$x, :$y);
(de dbl (P)
}
(if (is_zero P)
multi infix:<*>(Int $n where $n > 2, Point $p) {
P
2 * ($n div 2 * $p) + $n % 2 * $p;
(let
}
(Y
 
(*/
multi infix:<+>(Point $p, Point $q) {
if $p.x ~~ $q.x { 1.0
return $p.y ~~ $q.y ?? 2 (*/ $p3.0 !!(car Horizon;P) (car P) (** 1.0 2))
(*/ 2.0 (cadr P) 1.0) )
}
else { X
my $slope = ($q.y - $p.y) / ($q.x - $p.x);
my $y = $slope*($p.x - my $x = $slope(**2/ -Y $p.xY - $q1.x0) - $p.y;
return $p (*/ 2.new0 (:$x,car P) 1.0) ) :$y);
} (list
X
}
(-
 
say my $p = Point.new: x => $_, y => sqrt(abs(1 - $_**3 - $A (*$_/ Y (- $B(car P) X) given 1;.0)
say my $q = Point.new: x => $_, y => sqrt(abs(1 - $_**3 - $A*$_ -(cadr $BP) ) given) 2;) ) )
(de add (A B)
say my $s = $p + $q;
(cond
 
((= A B) (dbl A))
say "checking alignment: ", abs ($p.x - $q.x)*(-$s.y - $q.y) - ($p.y - $q.y)*($s.x - $q.x);</lang>
((is_zero A) B)
((is_zero B) A)
(T
(let Z (- (car B) (car A))
(if (=0 Z)
(list T T)
(let
(Y (*/ 1.0 (- (cadr B) (cadr A)) Z)
X
(- (*/ Y Y 1.0) (car A) (car B)) )
(list
X
(-
(*/ Y (- (car A) X) 1.0)
(cadr A) ) ) ) ) ) ) ) )
(de mul (P N)
(let R (list T T)
(for (I 1 (>= N I) (* I 2))
(when (gt0 (& I N))
(setq R (add R P)) )
(setq P (dbl P)) )
R ) )
(setq
A (from_y 1)
B (from_y 2) )
(prinl "A: " (prn A))
(prinl "B: " (prn B))
(setq C (add A B))
(prinl "C: " (prn C))
(setq D (neg C))
(prinl "D: " (prn D))
(prinl "D + C: " (prn (add C D)))
(prinl "A + B + D: " (prn (add A (add B D))))
(prinl "A * 12345: " (prn (mul A 12345)))</syntaxhighlight>
{{out}}
<pre>
<pre>EC Point at x=1, y=2.64575131106459
A: -1.817 1.000
EC Point at x=2, y=3.74165738677394
B: -1.442 2.000
EC Point at x=-1.79898987322333, y=0.421678696849803
C: 10.375 -33.525
checking alignment: 8.88178419700125e-16</pre>
D: 10.375 33.525
D + C: Zero
A + B + D: Zero
A * 12345: 10.759 35.387
</pre>
 
=={{header|Python}}==
{{trans|C}}
<langsyntaxhighlight lang="python">#!/usr/bin/env python3
 
class Point:
Line 773 ⟶ 1,951:
show("c + d =", c.add(d))
show("a + b + d =", a.add(b.add(d)))
show("a * 12345 =", a.mul(12345))</langsyntaxhighlight>
{{out}}
<pre>
Line 786 ⟶ 1,964:
 
=={{header|Racket}}==
<langsyntaxhighlight lang="racket">
#lang racket
(define a 0) (define b 7)
Line 813 ⟶ 1,991:
[(even? n) (⊗ (⊗ p (/ n 2)) 2)]
[(odd? n) (⊕ p (⊗ p (- n 1)))]))
</syntaxhighlight>
</lang>
Test:
<langsyntaxhighlight lang="racket">
(define (root3 x) (* (sgn x) (expt (abs x) 1/3)))
(define (y->point y) (vector (root3 (- (* y y) b)) y))
Line 827 ⟶ 2,005:
(displayln (~a "p+(q+(-(p+q))) = 0 " (zero? (⊕ p (⊕ q (neg (⊕ p q)))))))
(displayln (~a "p*12345 " (⊗ p 12345)))
</syntaxhighlight>
</lang>
Output:
<langsyntaxhighlight lang="racket">
p = #(-1.8171205928321397 1)
q = #(-1.4422495703074083 2)
Line 837 ⟶ 2,015:
p+(q+(-(p+q))) = 0 #t
p*12345 #(10.758570529320806 35.387434774282106)
</syntaxhighlight>
</lang>
 
=={{header|Raku}}==
(formerly Perl 6)
<syntaxhighlight lang="raku" line>module EC {
our ($A, $B) = (0, 7);
 
our class Point {
has ($.x, $.y);
multi method new(
$x, $y where $y**2 == $x**3 + $A*$x + $B
) { samewith :$x, :$y }
multi method gist { "EC Point at x=$.x, y=$.y" }
multi method gist(::?CLASS:U:) { 'Point at horizon' }
}
 
multi prefix:<->(Point $p) is export { Point.new: x => $p.x, y => -$p.y }
multi prefix:<->(Point:U) is export { Point }
multi infix:<->(Point $a, Point $b) is export { $a + -$b }
 
multi infix:<+>(Point:U $, Point $p) is export { $p }
multi infix:<+>(Point $p, Point:U) is export { $p }
 
multi infix:<*>(Point $u, Int $n) is export { $n * $u }
multi infix:<*>(Int $n, Point:U) is export { Point }
multi infix:<*>(0, Point) is export { Point }
multi infix:<*>(1, Point $p) is export { $p }
multi infix:<*>(2, Point $p) is export {
my $l = (3*$p.x**2 + $A) / (2 *$p.y);
my $y = $l*($p.x - my $x = $l**2 - 2*$p.x) - $p.y;
$p.new(:$x, :$y);
}
multi infix:<*>(Int $n where $n > 2, Point $p) is export {
2 * ($n div 2 * $p) + $n % 2 * $p;
}
 
multi infix:<+>(Point $p, Point $q) is export {
if $p.x ~~ $q.x {
return $p.y ~~ $q.y ?? 2 * $p !! Point;
}
else {
my $slope = ($q.y - $p.y) / ($q.x - $p.x);
my $y = $slope*($p.x - my $x = $slope**2 - $p.x - $q.x) - $p.y;
return $p.new(:$x, :$y);
}
}
 
}
 
import EC;
 
say my $p = EC::Point.new: x => $_, y => sqrt(abs($_**3 + $EC::A*$_ + $EC::B)) given 1;
say my $q = EC::Point.new: x => $_, y => sqrt(abs($_**3 + $EC::A*$_ + $EC::B)) given 2;
say my $s = $p + $q;
 
use Test;
is abs(($p.x - $q.x)*(-$s.y - $q.y) - ($p.y - $q.y)*($s.x - $q.x)), 0, "S, P and Q are aligned";</syntaxhighlight>
{{out}}
<pre>EC Point at x=1, y=2.8284271247461903
EC Point at x=2, y=3.872983346207417
EC Point at x=-1.9089023002066448, y=0.21008487055753378
ok 1 - S, P and Q are aligned</pre>
 
=={{header|REXX}}==
Line 844 ⟶ 2,083:
 
Also, some code was added to have the output better aligned &nbsp; (for instance, negative and positive numbers).
<langsyntaxhighlight lang="rexx">/*REXX program defines (for any 2 points on the curve), returns the sum of the 2 points.*/
numeric digits 100 /*try to ensure a min. of accuracy loss*/
a= func(1) ; say ' a = ' show(a)
b= func(2) ; say ' b = ' show(b)
c= add(a, b) ; say ' c = (a+b) =' show(c)
d= neg(c) ; say ' d = -c =' show(d)
e= add(c, d) ; say ' e = (c+d) =' show(e)
g= add(a, add(b, d)) ; say ' g = (a+b+d) =' show(g)
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
cbrt: procedure; parse arg x; return root(x,3)
conv: procedure; arg z; if isZ(z) then return 'zero'; return left('',z>=0)format(z,,5)/1
root: procedure; parse arg x,y; if x=0 | y=1 then return x/1; d=5; return rootI()/1
rootG: parse value format(x,2,1,,0) 'E0' with ? 'E' _ .; return (?/y'E'_ %y) + (x>1)
func: procedure; parse arg y,k; if k=='' then k=7; return cbrt(y**2-k) y
inf: return '1e' || (digits()%2)
isZ: procedure; parse arg px . ; return abs(px) >= inf()
neg: procedure; parse arg px py; return px (-py)
show: procedure; parse arg x y ; return conv(x) conv(y)
zero: return inf() inf()
/*──────────────────────────────────────────────────────────────────────────────────────*/
add: procedure; parse arg px py, qx qy; if px=qx & py=qy then return dbl(px py)
if isZ(px py) then return qx qy; if isZ(qx qy) then return px py
z=qx-px; if z=0 then do; $=inf(); rx=inf(); end
else do; $=(qy-py)/z; rx=$**2 - px - qx; end
ry=$ * (px-rx) - py
return rx ry
/*──────────────────────────────────────────────────────────────────────────────────────*/
convadd: procedure; parse arg z;px py, qx qy; if px=qx if& isZ(z)py=qy then return 'zero'dbl(px py)
if isZ(px py) then return qx qy; if isZ(qx qy) then return px return left('',z>=0)format(z,,5)/1py
z= qx - px; if z=0 then do; $= inf(); rx= inf(); end
else do; $= (qy-py) / z; rx= $*$ - px - qx; end
ry= $ * (px-rx) - py; return rx ry
/*──────────────────────────────────────────────────────────────────────────────────────*/
dbl: procedure; parse arg px py; if isZ(px py) then return px py; z= py+py*2
if z=0 then $= inf()
else $= (3*px*py) / (py*2+py)
rx= $**2$ - 2px*px; ry= $ * (px-rx) - py; return rx ry
return rx py
/*──────────────────────────────────────────────────────────────────────────────────────*/
rootI: ox=x; oy=y; x=abs(x); y=abs(y); a=digits()+5; numeric form; g=rootG(); m=y-1
do until d==a; d=min(d+d,a); numeric digits d; o=0
do until o=g; o=g; g=format((m*g**y+x)/y/g**m,,d-2); end /*until o=g*/
end /*until d==a*/; _=g*sign(ox); if oy<0 then _=1/_; return _</langsyntaxhighlight>
'''{{out|output'''}}
<pre>
a = -1.81712 1
b = -1.44225 2
c = (a+b) = 10.37538 -33.52451
d = -c = 10.37538 33.52451
e = (c+d) = zero zero
g = (a+b+d) = zero zero
</pre>
 
=={{header|Sage}}==
Examples from C, using the built-in Elliptic curves library.
<syntaxhighlight lang="sage">Ellie = EllipticCurve(RR,[0,7]) # RR = field of real numbers
<lang sage>
Ellie = EllipticCurve(RR,[0,7]) # RR = field of real numbers
 
# a point (x,y) on Ellie, given y
Line 897 ⟶ 2,140:
return P
 
print (Ellie)
P = point(1)
print ('P',P)
Q = point(2)
print ('Q',Q)
S = P+Q
print ('S = P + Q',S)
print ('P+Q-S', P+Q-S)
print ('P*12345' ,P*12345)</syntaxhighlight>
 
</lang>
{{out}}
<pre>
Line 918 ⟶ 2,159:
P+Q-S (0.000000000000000 : 1.00000000000000 : 0.000000000000000) ## Zero
P*12345 (10.7585721817304 : 35.3874428812067 : 1.00000000000000)
</pre>
 
=={{header|Sidef}}==
{{trans|Raku}}
<syntaxhighlight lang="ruby">module EC {
 
var A = 0
var B = 7
 
class Horizon {
method to_s {
"EC Point at horizon"
}
 
method *(_) {
self
}
 
method -(_) {
self
}
}
 
class Point(Number x, Number y) {
method to_s {
"EC Point at x=#{x}, y=#{y}"
}
 
method neg {
Point(x, -y)
}
 
method -(Point p) {
self + -p
}
 
method +(Point p) {
 
if (x == p.x) {
return (y == p.y ? self*2 : Horizon())
}
else {
var slope = (p.y - y)/(p.x - x)
var x2 = (slope**2 - x - p.x)
var y2 = (slope * (x - x2) - y)
Point(x2, y2)
}
}
 
method +(Horizon _) {
self
}
 
method *((0)) {
Horizon()
}
 
method *((1)) {
self
}
 
method *((2)) {
var l = (3 * x**2 + A)/(2 * y)
var x2 = (l**2 - 2*x)
var y2 = (l * (x - x2) - y)
Point(x2, y2)
}
 
method *(Number n) {
2*(self * (n>>1)) + self*(n % 2)
}
}
 
class Horizon {
method +(Point p) {
p
}
}
 
class Number {
method +(Point p) {
p + self
}
method *(Point p) {
p * self
}
method *(Horizon h) {
h
}
method -(Point p) {
-p + self
}
}
}
 
say var p = with(1) {|v| EC::Point(v, sqrt(abs(1 - v**3 - EC::A*v - EC::B))) }
say var q = with(2) {|v| EC::Point(v, sqrt(abs(1 - v**3 - EC::A*v - EC::B))) }
say var s = (p + q)
 
say ("checking alignment: ", abs((p.x - q.x)*(-s.y - q.y) - (p.y - q.y)*(s.x - q.x)) < 1e-20)</syntaxhighlight>
{{out}}
<pre>
EC Point at x=1, y=2.64575131106459059050161575363926042571025918308
EC Point at x=2, y=3.74165738677394138558374873231654930175601980778
EC Point at x=-1.79898987322333068322364213893577309997540625528, y=0.421678696849803028974882458314430376814790014487
checking alignment: true
</pre>
 
=={{header|Tcl}}==
{{trans|C}}
<langsyntaxhighlight lang="tcl">set C 7
set zero {x inf y inf}
proc tcl::mathfunc::cuberoot n {
Line 965 ⟶ 2,312:
}
return $r
}</langsyntaxhighlight>
Demonstrating:
<langsyntaxhighlight lang="tcl">proc show {s p} {
if {[iszero $p]} {
puts "${s}Zero"
Line 989 ⟶ 2,336:
show "c + d = " [add $c $d]
show "a + b + d = " [add $a [add $b $d]]
show "a * 12345 = " [multiply $a 12345]</langsyntaxhighlight>
{{out}}
<pre>
a = (-1.817, 1.000)
b = (-1.442, 2.000)
c = a + b = (10.375, -33.525)
d = -c = (10.375, 33.525)
c + d = Zero
a + b + d = Zero
a * 12345 = (10.759, 35.387)
</pre>
 
=={{header|V (Vlang)}}==
{{trans|go}}
<syntaxhighlight lang="v (vlang)">import math
 
const b_coeff = 7
struct Pt {
x f64
y f64
}
fn zero() Pt {
return Pt{math.inf(1), math.inf(1)}
}
fn is_zero(p Pt) bool {
return p.x > 1e20 || p.x < -1e20
}
fn neg(p Pt) Pt {
return Pt{p.x, -p.y}
}
fn dbl(p Pt) Pt {
if is_zero(p) {
return p
}
l := (3 * p.x * p.x) / (2 * p.y)
x := l*l - 2*p.x
return Pt{
x: x,
y: l*(p.x-x) - p.y,
}
}
fn add(p Pt, q Pt) Pt {
if p.x == q.x && p.y == q.y {
return dbl(p)
}
if is_zero(p) {
return q
}
if is_zero(q) {
return p
}
l := (q.y - p.y) / (q.x - p.x)
x := l*l - p.x - q.x
return Pt{
x: x,
y: l*(p.x-x) - p.y,
}
}
fn mul(mut p Pt, n int) Pt {
mut r := zero()
for i := 1; i <= n; i <<= 1 {
if i&n != 0 {
r = add(r, p)
}
p = dbl(p)
}
return r
}
fn show(s string, p Pt) {
print("$s")
if is_zero(p) {
println("Zero")
} else {
println("(${p.x:.3f}, ${p.y:.3f})")
}
}
fn from_y(y f64) Pt {
return Pt{
x: math.cbrt(y*y - b_coeff),
y: y,
}
}
fn main() {
mut a := from_y(1)
b := from_y(2)
show("a = ", a)
show("b = ", b)
c := add(a, b)
show("c = a + b = ", c)
d := neg(c)
show("d = -c = ", d)
show("c + d = ", add(c, d))
show("a + b + d = ", add(a, add(b, d)))
show("a * 12345 = ", mul(mut a, 12345))
}</syntaxhighlight>
 
{{out}}
<pre>
a = (-1.817, 1.000)
b = (-1.442, 2.000)
c = a + b = (10.375, -33.525)
d = -c = (10.375, 33.525)
c + d = Zero
a + b + d = Zero
a * 12345 = (10.759, 35.387)
</pre>
 
=={{header|Wren}}==
{{trans|C}}
{{libheader|Wren-fmt}}
<syntaxhighlight lang="wren">import "./fmt" for Fmt
 
var C = 7
 
class Pt {
static zero { Pt.new(1/0, 1/0) }
 
construct new(x, y) {
_x = x
_y = y
}
 
x { _x }
y { _y }
 
static fromNum(n) { Pt.new((n*n - C).cbrt, n) }
 
isZero { x > 1e20 || x < -1e20 }
 
double {
if (isZero) return this
var l = 3 * x * x / (2 * y)
var t = l*l - 2*x
return Pt.new(t, l*(x - t) - y)
}
 
- { Pt.new(x, -y) }
 
+(other) {
if (other.type != Pt) Fiber.abort("Argument must be a Pt object.")
if (x == other.x && y == other.y) return double
if (isZero) return other
if (other.isZero) return this
var l = (other.y - y) / (other.x - x)
var t = l*l - x - other.x
return Pt.new(t, l*(x-t) - y)
}
 
*(n) {
if (n.type != Num || !n.isInteger) {
Fiber.abort("Argument must be an integer.")
}
var r = Pt.zero
var p = this
var i = 1
while (i <= n) {
if ((i & n) != 0) r = r + p
p = p.double
i = i << 1
}
return r
}
 
toString { isZero ? "Zero" : Fmt.swrite("($0.3f, $0.3f)", x, y) }
}
 
var a = Pt.fromNum(1)
var b = Pt.fromNum(2)
var c = a + b
var d = -c
System.print("a = %(a)")
System.print("b = %(b)")
System.print("c = a + b = %(c)")
System.print("d = -c = %(d)")
System.print("c + d = %(c + d)")
System.print("a + b + d = %(a + b + d)")
System.print("a * 12345 = %(a * 12345)")</syntaxhighlight>
 
{{out}}
<pre>
a = (-1.817, 1.000)
b = (-1.442, 2.000)
c = a + b = (10.375, -33.525)
d = -c = (10.375, 33.525)
c + d = Zero
a + b + d = Zero
a * 12345 = (10.759, 35.388)
</pre>
 
=={{header|zkl}}==
{{trans|C}}
<syntaxhighlight lang="zkl">const C=7, INFINITY=(0.0).inf;
 
fcn zero{ T(INFINITY, INFINITY) }
 
// should be INFINITY, but numeric precision is very much in the way
fcn is_zero(p){ x,_:=p; (x < -1e20 or x > 1e20) }
 
fcn neg(p){ return(p[0], -p[1]) }
fcn dbl(p){
if(is_zero(p)) return(p);
 
px,py := p;
L:=(3.0 * px * px) / (2.0 * py);
rx,ry := L * L - 2.0 * px, L * (px - rx) - py;
return(rx,ry);
}
fcn add(p,q){
px,py := p;
qx,qy := q;
if(px == qx and py == qy) return(dbl(p));
if(is_zero(p)) return(q);
if(is_zero(q)) return(p);
L := (qy - py) / (qx - px);
rx,ry := L * L - px - qx, L * (px - rx) - py;
return(rx,ry);
}
fcn mul(p,n){
r := zero();
i:=1; while(i <= n){
if(i.bitAnd(n)) r = add(r,p);
p = dbl(p);
i*=2;
}
r
}</syntaxhighlight>
<syntaxhighlight lang="zkl">fcn show(str,p)
{ println(str, is_zero(p) and "Zero" or "(%.3f, %.3f)".fmt(p.xplode())) }
fcn from_y(y){
y3:=y * y - C; // cube root of -6 --> -1.817
return(y3.abs().pow(1.0/3) * y3.sign, y)
}
a,b := from_y(1.0), from_y(2.0);
show("a = ", a);
show("b = ", b);
show("c = a + b = ", c := add(a, b));
show("d = -c = ", d := neg(c));
show("c + d = ", add(c, d));
show("a + b + d = ", add(a, add(b, d)));
show("a * 12345 = ", mul(a, 12345.0));</syntaxhighlight>
{{out}}
<pre>
9,477

edits