Data update
This commit is contained in:
parent
4d5544505c
commit
4924dd0264
3073 changed files with 55820 additions and 4408 deletions
211
Task/Elliptic-curve-arithmetic/Rust/elliptic-curve-arithmetic.rs
Normal file
211
Task/Elliptic-curve-arithmetic/Rust/elliptic-curve-arithmetic.rs
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
use std::fmt;
|
||||
use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Neg};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct EllipticPoint {
|
||||
x: f64,
|
||||
y: f64,
|
||||
}
|
||||
|
||||
impl EllipticPoint {
|
||||
const ZERO_THRESHOLD: f64 = 1e20;
|
||||
const B: f64 = 7.0; // the 'b' in y^2 = x^3 + a * x + b, where 'a' is 0
|
||||
|
||||
/// Create a point that is initialized to Zero (point at infinity)
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
x: 0.0,
|
||||
y: Self::ZERO_THRESHOLD * 1.01,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a point based on the y-coordinate. For a curve with a = 0 and b = 7
|
||||
/// there is only one x for each y
|
||||
pub fn from_y(y_coordinate: f64) -> Self {
|
||||
let y = y_coordinate;
|
||||
let x = (y * y - Self::B).cbrt();
|
||||
Self { x, y }
|
||||
}
|
||||
|
||||
/// Check if the point is zero (point at infinity)
|
||||
pub fn is_zero(&self) -> bool {
|
||||
// when the elliptic point is at zero, y = +/- infinity
|
||||
self.y.abs() >= Self::ZERO_THRESHOLD
|
||||
}
|
||||
|
||||
/// Double the point (multiply by 2)
|
||||
fn double(&mut self) {
|
||||
if self.is_zero() {
|
||||
// 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 self.y == 0.0 {
|
||||
// at this point the tangent to the curve is vertical.
|
||||
// this point doubled is 0
|
||||
*self = EllipticPoint::new();
|
||||
} else {
|
||||
let l = (3.0 * self.x * self.x) / (2.0 * self.y);
|
||||
let new_x = l * l - 2.0 * self.x;
|
||||
self.y = l * (self.x - new_x) - self.y;
|
||||
self.x = new_x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for EllipticPoint {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for EllipticPoint {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if self.is_zero() {
|
||||
write!(f, "(Zero)")
|
||||
} else {
|
||||
write!(f, "({}, {})", self.x, self.y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Neg for EllipticPoint {
|
||||
type Output = Self;
|
||||
|
||||
fn neg(self) -> Self::Output {
|
||||
Self {
|
||||
x: self.x,
|
||||
y: -self.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for EllipticPoint {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
let mut result = self;
|
||||
result += rhs;
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for EllipticPoint {
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
if self.is_zero() {
|
||||
*self = rhs;
|
||||
} else if rhs.is_zero() {
|
||||
// since rhs is zero this point does not need to be modified
|
||||
} else {
|
||||
let l = (rhs.y - self.y) / (rhs.x - self.x);
|
||||
if l.is_finite() {
|
||||
let new_x = l * l - self.x - rhs.x;
|
||||
self.y = l * (self.x - new_x) - self.y;
|
||||
self.x = new_x;
|
||||
} else {
|
||||
if self.y.is_sign_negative() != rhs.y.is_sign_negative() {
|
||||
// in this case rhs == -lhs, the result should be 0
|
||||
*self = EllipticPoint::new();
|
||||
} else {
|
||||
// in this case rhs == lhs.
|
||||
self.double();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for EllipticPoint {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
self + (-rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign for EllipticPoint {
|
||||
fn sub_assign(&mut self, rhs: Self) {
|
||||
*self += -rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<i32> for EllipticPoint {
|
||||
type Output = Self;
|
||||
|
||||
fn mul(self, rhs: i32) -> Self::Output {
|
||||
let mut result = self;
|
||||
result *= rhs;
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<EllipticPoint> for i32 {
|
||||
type Output = EllipticPoint;
|
||||
|
||||
fn mul(self, rhs: EllipticPoint) -> Self::Output {
|
||||
rhs * self
|
||||
}
|
||||
}
|
||||
|
||||
impl MulAssign<i32> for EllipticPoint {
|
||||
fn mul_assign(&mut self, mut rhs: i32) {
|
||||
let mut r = EllipticPoint::new();
|
||||
let mut p = *self;
|
||||
|
||||
if rhs < 0 {
|
||||
// change p * -rhs to -p * rhs
|
||||
rhs = -rhs;
|
||||
p = -p;
|
||||
}
|
||||
|
||||
let mut i = 1;
|
||||
while i <= rhs {
|
||||
if (i & rhs) != 0 {
|
||||
r += p;
|
||||
}
|
||||
p.double();
|
||||
i <<= 1;
|
||||
}
|
||||
|
||||
*self = r;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let a = EllipticPoint::from_y(1.0);
|
||||
let b = EllipticPoint::from_y(2.0);
|
||||
|
||||
println!("a = {}", a);
|
||||
println!("b = {}", b);
|
||||
|
||||
let c = a + b;
|
||||
println!("c = a + b = {}", c);
|
||||
println!("a + b - c = {}", a + b - c);
|
||||
println!("a + b - (b + a) = {}\n", a + b - (b + a));
|
||||
|
||||
println!("a + a + a + a + a - 5 * a = {}", a + a + a + a + a - 5 * a);
|
||||
println!("a * 12345 = {}", a * 12345);
|
||||
println!("a * -12345 = {}", a * -12345);
|
||||
println!("a * 12345 + a * -12345 = {}", a * 12345 + a * -12345);
|
||||
println!("a * 12345 - (a * 12000 + a * 345) = {}", a * 12345 - (a * 12000 + a * 345));
|
||||
println!("a * 12345 - (a * 12001 + a * 345) = {}\n", a * 12345 - (a * 12000 + a * 344));
|
||||
|
||||
let zero = EllipticPoint::new();
|
||||
let mut g = EllipticPoint::new();
|
||||
println!("g = zero = {}", g);
|
||||
g += a;
|
||||
println!("g += a = {}", g);
|
||||
g += zero;
|
||||
println!("g += zero = {}", g);
|
||||
g += b;
|
||||
println!("g += b = {}", g);
|
||||
println!("b + b - b * 2 = {}\n", b + b - b * 2);
|
||||
|
||||
let mut special = EllipticPoint::from_y(0.0); // the point where the curve crosses the x-axis
|
||||
println!("special = {}", special); // this has the minimum possible value for x
|
||||
special *= 2;
|
||||
println!("special *= 2 = {}", special); // doubling it gives zero
|
||||
}
|
||||
187
Task/Elliptic-curve-arithmetic/Zig/elliptic-curve-arithmetic.zig
Normal file
187
Task/Elliptic-curve-arithmetic/Zig/elliptic-curve-arithmetic.zig
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
const std = @import("std");
|
||||
const math = std.math;
|
||||
const print = std.debug.print;
|
||||
|
||||
const EllipticPoint = struct {
|
||||
x: f64,
|
||||
y: f64,
|
||||
|
||||
const ZERO_THRESHOLD: f64 = 1e20;
|
||||
const B: f64 = 7.0; // the 'b' in y^2 = x^3 + a * x + b, where 'a' is 0
|
||||
|
||||
/// Create a point that is initialized to Zero (point at infinity)
|
||||
pub fn new() EllipticPoint {
|
||||
return EllipticPoint{
|
||||
.x = 0.0,
|
||||
.y = ZERO_THRESHOLD * 1.01,
|
||||
};
|
||||
}
|
||||
|
||||
/// Create a point based on the y-coordinate. For a curve with a = 0 and b = 7
|
||||
/// there is only one x for each y
|
||||
pub fn fromY(y_coordinate: f64) EllipticPoint {
|
||||
const y = y_coordinate;
|
||||
const x = math.cbrt(y * y - B);
|
||||
return EllipticPoint{ .x = x, .y = y };
|
||||
}
|
||||
|
||||
/// Check if the point is zero (point at infinity)
|
||||
pub fn isZero(self: EllipticPoint) bool {
|
||||
// when the elliptic point is at zero, y = +/- infinity
|
||||
return @abs(self.y) >= ZERO_THRESHOLD;
|
||||
}
|
||||
|
||||
/// Double the point (multiply by 2)
|
||||
pub fn double(self: *EllipticPoint) void {
|
||||
if (self.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 (self.y == 0.0) {
|
||||
// at this point the tangent to the curve is vertical.
|
||||
// this point doubled is 0
|
||||
self.* = EllipticPoint.new();
|
||||
} else {
|
||||
const l = (3.0 * self.x * self.x) / (2.0 * self.y);
|
||||
const new_x = l * l - 2.0 * self.x;
|
||||
self.y = l * (self.x - new_x) - self.y;
|
||||
self.x = new_x;
|
||||
}
|
||||
}
|
||||
|
||||
/// Negate the point
|
||||
pub fn neg(self: EllipticPoint) EllipticPoint {
|
||||
return EllipticPoint{
|
||||
.x = self.x,
|
||||
.y = -self.y,
|
||||
};
|
||||
}
|
||||
|
||||
/// Add two points
|
||||
pub fn add(self: EllipticPoint, rhs: EllipticPoint) EllipticPoint {
|
||||
var result = self;
|
||||
result.addAssign(rhs);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Add a point to this point (mutating)
|
||||
pub fn addAssign(self: *EllipticPoint, rhs: EllipticPoint) void {
|
||||
if (self.isZero()) {
|
||||
self.* = rhs;
|
||||
} else if (rhs.isZero()) {
|
||||
// since rhs is zero this point does not need to be modified
|
||||
} else {
|
||||
const l = (rhs.y - self.y) / (rhs.x - self.x);
|
||||
if (math.isFinite(l)) {
|
||||
const new_x = l * l - self.x - rhs.x;
|
||||
self.y = l * (self.x - new_x) - self.y;
|
||||
self.x = new_x;
|
||||
} else {
|
||||
if (math.signbit(self.y) != math.signbit(rhs.y)) {
|
||||
// in this case rhs == -lhs, the result should be 0
|
||||
self.* = EllipticPoint.new();
|
||||
} else {
|
||||
// in this case rhs == lhs.
|
||||
self.double();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Subtract two points
|
||||
pub fn sub(self: EllipticPoint, rhs: EllipticPoint) EllipticPoint {
|
||||
return self.add(rhs.neg());
|
||||
}
|
||||
|
||||
/// Subtract a point from this point (mutating)
|
||||
pub fn subAssign(self: *EllipticPoint, rhs: EllipticPoint) void {
|
||||
self.addAssign(rhs.neg());
|
||||
}
|
||||
|
||||
/// Multiply point by an integer scalar
|
||||
pub fn mul(self: EllipticPoint, scalar: i32) EllipticPoint {
|
||||
var result = self;
|
||||
result.mulAssign(scalar);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Multiply this point by an integer scalar (mutating)
|
||||
pub fn mulAssign(self: *EllipticPoint, scalar: i32) void {
|
||||
var r = EllipticPoint.new();
|
||||
var p = self.*;
|
||||
var rhs = scalar;
|
||||
|
||||
if (rhs < 0) {
|
||||
// change p * -rhs to -p * rhs
|
||||
rhs = -rhs;
|
||||
p = p.neg();
|
||||
}
|
||||
|
||||
var i: i32 = 1;
|
||||
while (i <= rhs) {
|
||||
if ((i & rhs) != 0) {
|
||||
r.addAssign(p);
|
||||
}
|
||||
p.double();
|
||||
i <<= 1;
|
||||
}
|
||||
|
||||
self.* = r;
|
||||
}
|
||||
|
||||
/// Format the point for printing
|
||||
pub fn format(
|
||||
self: EllipticPoint,
|
||||
comptime fmt: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
_ = fmt;
|
||||
_ = options;
|
||||
if (self.isZero()) {
|
||||
try writer.print("(Zero)", .{});
|
||||
} else {
|
||||
try writer.print("({d}, {d})", .{ self.x, self.y });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub fn main() !void {
|
||||
const a = EllipticPoint.fromY(1.0);
|
||||
const b = EllipticPoint.fromY(2.0);
|
||||
|
||||
print("a = {}\n", .{a});
|
||||
print("b = {}\n", .{b});
|
||||
|
||||
const c = a.add(b);
|
||||
print("c = a + b = {}\n", .{c});
|
||||
print("a + b - c = {}\n", .{a.add(b).sub(c)});
|
||||
print("a + b - (b + a) = {}\n\n", .{a.add(b).sub(b.add(a))});
|
||||
|
||||
print("a + a + a + a + a - 5 * a = {}\n", .{a.add(a).add(a).add(a).add(a).sub(a.mul(5))});
|
||||
print("a * 12345 = {}\n", .{a.mul(12345)});
|
||||
print("a * -12345 = {}\n", .{a.mul(-12345)});
|
||||
print("a * 12345 + a * -12345 = {}\n", .{a.mul(12345).add(a.mul(-12345))});
|
||||
print("a * 12345 - (a * 12000 + a * 345) = {}\n", .{a.mul(12345).sub(a.mul(12000).add(a.mul(345)))});
|
||||
print("a * 12345 - (a * 12001 + a * 345) = {}\n\n", .{a.mul(12345).sub(a.mul(12000).add(a.mul(344)))});
|
||||
|
||||
const zero = EllipticPoint.new();
|
||||
var g = EllipticPoint.new();
|
||||
print("g = zero = {}\n", .{g});
|
||||
g.addAssign(a);
|
||||
print("g += a = {}\n", .{g});
|
||||
g.addAssign(zero);
|
||||
print("g += zero = {}\n", .{g});
|
||||
g.addAssign(b);
|
||||
print("g += b = {}\n", .{g});
|
||||
print("b + b - b * 2 = {}\n\n", .{b.add(b).sub(b.mul(2))});
|
||||
|
||||
var special = EllipticPoint.fromY(0.0); // the point where the curve crosses the x-axis
|
||||
print("special = {}\n", .{special}); // this has the minimum possible value for x
|
||||
special.mulAssign(2);
|
||||
print("special *= 2 = {}\n", .{special}); // doubling it gives zero
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue