%%
% This script is for adding two points on an elliptic curve over a finite
% field of size of a prime p that is given in the short weierstrass form.
% note that p should not be excessively large, as many computations here
% rely on bruteforcing.
clc ; clear;
% Field characteristic p ~= 2 , 3
p = 17 ;
% Parameters of the elliptic curve y^ 2 = x^ 3 + Ax + B
A = 2 ;
B = 2 ;
% Points you want to add
P = [ 5 , 1 ] ; % two coordinates [ x, y] or just Inf for the neutral element
Q = [ 7 , 6 ] ; % write P= Inf; Q= Inf; to find all points on the curve
% DO NOT CHANGE ANYTHING BELOW THIS LINE
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
F= @( x, y) mod( x.^ 3 + A* x + B - y.^ 2 , p) ;
%% perform checks
assert ( mod
( 4 * A
^ 3 + 27 * B
^ 2 , p
) ~
= 0 , 'A,B do not define an elliptic curve' ) ; assert ( p~
= 2 && p~
= 3 && isprime
( p
) , 'p=2,3 or p is not prime' ) ; assert ( P
( 1 ) == Inf
|| F
( P
( 1 ) , P
( 2 ) ) == 0 , 'P is not on the curve' ) ; assert ( Q
( 1 ) == Inf
|| F
( Q
( 1 ) , Q
( 2 ) ) == 0 , 'Q is not on the curve' ) ;
%% find all points
all_points = [ ] ;
for x= 0 : p- 1 ;
for y= 0 : p- 1 ;
if F( x, y) == 0
all_points = [ all_points; x, y] ;
end
end
end
disp( 'all points on the curve are the following:' ) ;
disp( ' inf' ) ;
disp( all_points)
%% tree
if P == Inf % P is neutral element
disp( 'Result is:' )
disp( Q)
elseif Q == Inf % Q is neutral element
disp( 'Result is:' )
disp( P)
else
disp( 'apparently none of the summands is the neutral element...' ) ;
if P( 1 ) == Q( 1 ) && mod( P( 2 ) + Q( 2 ) , p) == 0 % P+ Q == 0
disp( 'Result is:' )
disp( Inf)
else % P ~= - Q -> we have a nonvertical line
disp( 'P and Q are apparently not additive inverses to each other...' ) ;
x0 = P( 1 ) ;
y0 = P( 2 ) ;
x1 = Q( 1 ) ;
y1 = Q( 2 ) ;
if x0 == x1 && y0 == y1; % P == Q -> calcualte tangent
disp( 'we have to double P == Q ...' ) ;
% m = ( 3 * x0^ 2 + A) / ( 2 * y0) ;
% find modular inverse of ( 2 * y0)
k = find( mod( ( 1 : p) * 2 * y0, p) == 1 ) ;
m = mod( ( 3 * x0^ 2 + A) * k, p) ;
q = mod( ( - x0^ 3 + A* x0 + 2 * B) * k, p) ;
else % calculate line ( nonvertical) throu those two points
disp( 'we can calculate a nonvertical line throu P and Q...' ) ;
% m = ( y1- y0) / ( x1- x0)
% find modular inverse of ( x1- x0)
k = find( mod( ( 1 : p) * ( x1- x0) , p) == 1 ) ;
m = mod( ( y1- y0) * k, p) ;
% q = y0 - m* x0
q = mod( y0 - m* x0, p) ;
end
% calculate the zeros of this polynomial:
% P = x^ 3 + Ax+ B - ( m* x+ q) ^ 2
% = x^ 3 + Ax+ B - ( m^ 2 * x^ 2 + 2 * m* q* x+ q^ 2 )
% = x^ 3 + ( - m^ 2 ) * x^ 2 + ( A- 2 * m* q) * x + ( B- q^ 2 )
pl = mod( [ 1 , - m^ 2 , A- 2 * m* q, B- q^ 2 ] , p) ;
pl_roots = mod( find( mod( polyval( pl, 1 : p) , p) == 0 , 3 ) , p) ;
if numel( pl_roots) == 3
disp( 'the polynomial has 3 distinct roots...' ) ;
X = pl_roots( pl_roots ~= x0 & pl_roots ~= x1) ;
Y = mod( m* X+ q, p) ;
disp( 'Result is:' ) ;
disp( mod( [ X,- Y] , p) ) ;
elseif numel( pl_roots) == 2 ;
disp( 'the polynomial has 2 distinct roots...' ) ;
if all( mod( conv( conv( [ 1 ,- x0] , [ 1 ,- x1] ) , [ 1 ,- pl_roots( 1 ) ] ) , p) == pl)
disp( 'Result is:' )
X = pl_roots( 1 ) ;
Y = mod( m* X+ q, p) ;
disp( mod( [ X,- Y] , p) ) ;
elseif all( mod( conv( conv( [ 1 ,- x0] , [ 1 ,- x1] ) , [ 1 ,- pl_roots( 2 ) ] ) , p) == pl)
disp( 'Result is:' ) ;
X = pl_roots( 2 ) ;
Y = mod( m* X+ q, p) ;
disp( mod( [ X,- Y] , p) ) ;
else
disp( 'ERROR: something went horribly wrong: could not reconstruct polynomial' ) ;
end
elseif numel( pl_roots) == 1 ;
disp( 'the polynomial has 1 distinct root...' ) ;
if all( mod( conv( conv( [ 1 ,- x0] , [ 1 ,- x1] ) , [ 1 ,- pl_roots] ) , p) == pl)
disp( 'Result is:' )
X = pl_roots;
Y = mod( m* X+ q, p) ;
disp( mod( [ X,- Y] , p) )
else
disp( 'ERROR: somethign went horribly wrong: could not reconstruct polynomial' ) ;
end
else
disp( 'ERROR: something went horribly wrong (not 1 or 2 or 3 roots)' ) ;
end
end
end
JSUKJSBUaGlzIHNjcmlwdCBpcyBmb3IgYWRkaW5nIHR3byBwb2ludHMgb24gYW4gZWxsaXB0aWMgY3VydmUgb3ZlciBhIGZpbml0ZQolIGZpZWxkIG9mIHNpemUgb2YgYSBwcmltZSBwIHRoYXQgaXMgZ2l2ZW4gaW4gdGhlIHNob3J0IHdlaWVyc3RyYXNzIGZvcm0uCiUgbm90ZSB0aGF0IHAgc2hvdWxkIG5vdCBiZSBleGNlc3NpdmVseSBsYXJnZSwgYXMgbWFueSBjb21wdXRhdGlvbnMgaGVyZQolIHJlbHkgb24gYnJ1dGVmb3JjaW5nLgoKCmNsYztjbGVhcjsKJSBGaWVsZCBjaGFyYWN0ZXJpc3RpYyBwIH49IDIsMwpwID0gMTc7CiUgUGFyYW1ldGVycyBvZiB0aGUgZWxsaXB0aWMgY3VydmUgeV4yID0geF4zICsgQXggKyBCCkEgPSAyOwpCID0gMjsgCgolIFBvaW50cyB5b3Ugd2FudCB0byBhZGQKClAgPSBbNSwxXTsgJSB0d28gY29vcmRpbmF0ZXMgW3gseV0gb3IganVzdCBJbmYgZm9yIHRoZSBuZXV0cmFsIGVsZW1lbnQKUSA9IFs3LDZdOyAlIHdyaXRlIFA9SW5mOyBRPUluZjsgdG8gZmluZCBhbGwgcG9pbnRzIG9uIHRoZSBjdXJ2ZQoKJSBETyBOT1QgQ0hBTkdFIEFOWVRISU5HIEJFTE9XIFRISVMgTElORQolJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlCgoKRj1AKHgseSkgbW9kKHguXjMgKyBBKnggKyBCIC0geS5eMixwKTsKCgolJSBwZXJmb3JtIGNoZWNrcwphc3NlcnQobW9kKDQqQV4zICsgMjcqQl4yLCBwKSB+PTAsJ0EsQiBkbyBub3QgZGVmaW5lIGFuIGVsbGlwdGljIGN1cnZlJyk7CmFzc2VydChwfj0yICYmIHB+PTMgJiYgaXNwcmltZShwKSwncD0yLDMgb3IgcCBpcyBub3QgcHJpbWUnKTsKYXNzZXJ0KFAoMSkgPT0gSW5mIHx8IEYoUCgxKSxQKDIpKSA9PSAwICwgJ1AgaXMgbm90IG9uIHRoZSBjdXJ2ZScpOwphc3NlcnQoUSgxKSA9PSBJbmYgfHwgRihRKDEpLFEoMikpID09IDAgLCAnUSBpcyBub3Qgb24gdGhlIGN1cnZlJyk7CgolJSBmaW5kIGFsbCBwb2ludHMKYWxsX3BvaW50cyA9IFtdOwpmb3IgeD0wOnAtMTsKICAgIGZvciB5PTA6cC0xOwogICAgICAgIGlmIEYoeCx5KT09MAogICAgICAgICAgICBhbGxfcG9pbnRzID0gW2FsbF9wb2ludHM7IHgseV07CiAgICAgICAgZW5kCiAgICBlbmQKZW5kCmRpc3AoJ2FsbCBwb2ludHMgb24gdGhlIGN1cnZlIGFyZSB0aGUgZm9sbG93aW5nOicpOwpkaXNwKCcgICAgIGluZicpOwpkaXNwKGFsbF9wb2ludHMpCgoKJSUgdHJlZQoKaWYgUCA9PSBJbmYgICAgICUgUCBpcyBuZXV0cmFsIGVsZW1lbnQKICAgIGRpc3AoJ1Jlc3VsdCBpczonKQogICAgZGlzcChRKQplbHNlaWYgUSA9PSBJbmYgJSBRIGlzIG5ldXRyYWwgZWxlbWVudAogICAgZGlzcCgnUmVzdWx0IGlzOicpCiAgICBkaXNwKFApCmVsc2UKICAgIGRpc3AoJ2FwcGFyZW50bHkgbm9uZSBvZiB0aGUgc3VtbWFuZHMgaXMgdGhlIG5ldXRyYWwgZWxlbWVudC4uLicpOwogICAgaWYgUCgxKSA9PSBRKDEpICYmIG1vZChQKDIpK1EoMikscCkgPT0gMCAlIFArUSA9PSAwCiAgICAgICAgZGlzcCgnUmVzdWx0IGlzOicpCiAgICAgICAgZGlzcChJbmYpCiAgICBlbHNlICAlIFAgfj0gLVEgLT4gd2UgaGF2ZSBhIG5vbnZlcnRpY2FsIGxpbmUKICAgICAgICBkaXNwKCdQIGFuZCBRIGFyZSBhcHBhcmVudGx5IG5vdCBhZGRpdGl2ZSBpbnZlcnNlcyB0byBlYWNoIG90aGVyLi4uJyk7CiAgICAgICAgeDAgPSBQKDEpOwogICAgICAgIHkwID0gUCgyKTsKICAgICAgICB4MSA9IFEoMSk7CiAgICAgICAgeTEgPSBRKDIpOwogICAgICAgIGlmIHgwID09IHgxICYmIHkwID09IHkxOyAlIFAgPT0gUSAtPiBjYWxjdWFsdGUgdGFuZ2VudAogICAgICAgICAgICBkaXNwKCd3ZSBoYXZlIHRvIGRvdWJsZSBQID09IFEgLi4uJyk7CiAgICAgICAgICAgICUgbSA9ICgzKiB4MF4yICsgQSkvICgyICogeTApOwogICAgICAgICAgICAlIGZpbmQgbW9kdWxhciBpbnZlcnNlIG9mICgyKnkwKQogICAgICAgICAgICBrID0gZmluZCggbW9kKCAoMTpwKSAqIDIqeTAsIHApID09IDEpOwogICAgICAgICAgICBtID0gbW9kKCgzKngwXjIgKyBBKSAqIGssIHApOwogICAgICAgICAgICBxID0gbW9kKCAoLXgwXjMrQSp4MCArIDIqQikgKiBrLCBwKTsKICAgICAgICAgICAgCgogICAgICAgIGVsc2UgICUgY2FsY3VsYXRlIGxpbmUgKG5vbnZlcnRpY2FsKSB0aHJvdSB0aG9zZSB0d28gcG9pbnRzCiAgICAgICAgICAgIGRpc3AoJ3dlIGNhbiBjYWxjdWxhdGUgYSBub252ZXJ0aWNhbCBsaW5lIHRocm91IFAgYW5kIFEuLi4nKTsKICAgICAgICAgICAgJSBtID0gKHkxLXkwKSAvICh4MS14MCkKICAgICAgICAgICAgJSBmaW5kIG1vZHVsYXIgaW52ZXJzZSBvZiAoeDEteDApCiAgICAgICAgICAgIGsgPSBmaW5kKCBtb2QoICgxOnApICogKHgxLXgwKSwgcCkgPT0gMSk7CiAgICAgICAgICAgIG0gPSBtb2QoICh5MS15MCkgKiBrLCBwKTsKICAgICAgICAgICAgJSBxID0geTAgLSBtKngwCiAgICAgICAgICAgIHEgPSBtb2QoIHkwIC0gbSp4MCwgcCk7CiAgICAgICAgZW5kCiAgICAgICAgJSBjYWxjdWxhdGUgdGhlIHplcm9zIG9mIHRoaXMgcG9seW5vbWlhbDoKICAgICAgICAgICAgJSBQID0geF4zK0F4K0IgLSAobSp4K3EpXjIgCiAgICAgICAgICAgICUgICA9IHheMytBeCtCIC0gKG1eMiAqIHheMiArIDIqbSpxKngrcV4yKQogICAgICAgICAgICAlICAgPSB4XjMgKyAoLW1eMikgKiB4XjIgKyAoQS0yKm0qcSkgKiB4ICsgKEItcV4yKQogICAgICAgIHBsID0gbW9kKFsxLCAtbV4yLCBBLTIqbSpxLCBCLXFeMl0sIHApOwogICAgICAgIHBsX3Jvb3RzID0gbW9kKGZpbmQobW9kKHBvbHl2YWwocGwsMTpwKSxwKT09MCwzKSxwKTsgCiAgICAgICAgCiAgICAgICAgaWYgbnVtZWwocGxfcm9vdHMpID09IDMKICAgICAgICAgICAgZGlzcCgndGhlIHBvbHlub21pYWwgaGFzIDMgZGlzdGluY3Qgcm9vdHMuLi4nKTsKICAgICAgICAgICAgWCA9IHBsX3Jvb3RzKCBwbF9yb290cyB+PSB4MCAmIHBsX3Jvb3RzIH49IHgxKTsKICAgICAgICAgICAgWSA9IG1vZChtKlgrcSwgcCk7CiAgICAgICAgICAgIGRpc3AoJ1Jlc3VsdCBpczonKTsKICAgICAgICAgICAgZGlzcChtb2QoW1gsLVldLHApKTsKICAgICAgICBlbHNlaWYgbnVtZWwocGxfcm9vdHMpID09IDI7CiAgICAgICAgICAgIGRpc3AoJ3RoZSBwb2x5bm9taWFsIGhhcyAyIGRpc3RpbmN0IHJvb3RzLi4uJyk7CiAgICAgICAgICAgIGlmIGFsbCggbW9kKGNvbnYoY29udihbMSwteDBdLFsxLC14MV0pLFsxLC1wbF9yb290cygxKV0pLHApID09IHBsKQogICAgICAgICAgICAgICAgZGlzcCgnUmVzdWx0IGlzOicpCiAgICAgICAgICAgICAgICBYID0gcGxfcm9vdHMoMSk7CiAgICAgICAgICAgICAgICBZID0gbW9kKG0qWCtxLCBwKTsKICAgICAgICAgICAgICAgIGRpc3AobW9kKFtYLC1ZXSxwKSk7CiAgICAgICAgICAgIGVsc2VpZiAgYWxsKCBtb2QoY29udihjb252KFsxLC14MF0sWzEsLXgxXSksWzEsLXBsX3Jvb3RzKDIpXSkscCkgPT0gcGwpCiAgICAgICAgICAgICAgICBkaXNwKCdSZXN1bHQgaXM6Jyk7CiAgICAgICAgICAgICAgICBYID0gcGxfcm9vdHMoMik7CiAgICAgICAgICAgICAgICBZID0gbW9kKG0qWCtxLCBwKTsKICAgICAgICAgICAgICAgIGRpc3AobW9kKFtYLC1ZXSxwKSk7CiAgICAgICAgICAgIGVsc2UKICAgICAgICAgICAgICAgZGlzcCgnRVJST1I6IHNvbWV0aGluZyB3ZW50IGhvcnJpYmx5IHdyb25nOiBjb3VsZCBub3QgcmVjb25zdHJ1Y3QgcG9seW5vbWlhbCcpOyAKICAgICAgICAgICAgZW5kCiAgICAgICAgZWxzZWlmIG51bWVsKHBsX3Jvb3RzKSA9PSAxOwogICAgICAgICAgICBkaXNwKCd0aGUgcG9seW5vbWlhbCBoYXMgMSBkaXN0aW5jdCByb290Li4uJyk7CiAgICAgICAgICAgIGlmIGFsbCggbW9kKGNvbnYoY29udihbMSwteDBdLFsxLC14MV0pLFsxLC1wbF9yb290c10pLHApID09IHBsKQogICAgICAgICAgICAgICAgZGlzcCgnUmVzdWx0IGlzOicpCiAgICAgICAgICAgICAgICBYID0gcGxfcm9vdHM7CiAgICAgICAgICAgICAgICBZID0gbW9kKG0qWCtxLCBwKTsKICAgICAgICAgICAgICAgIGRpc3AobW9kKFtYLC1ZXSxwKSkgIAogICAgICAgICAgICBlbHNlCiAgICAgICAgICAgICAgIGRpc3AoJ0VSUk9SOiBzb21ldGhpZ24gd2VudCBob3JyaWJseSB3cm9uZzogY291bGQgbm90IHJlY29uc3RydWN0IHBvbHlub21pYWwnKTsgCiAgICAgICAgICAgIGVuZAogICAgICAgICAgICAKICAgICAgICBlbHNlCiAgICAgICAgICAgIGRpc3AoJ0VSUk9SOiBzb21ldGhpbmcgd2VudCBob3JyaWJseSB3cm9uZyAobm90IDEgb3IgMiBvciAzIHJvb3RzKScpOwogICAgICAgIGVuZAogICAKICAgIGVuZAplbmQKICAgIAoK