note
	description: "Objects that ..."
	author: "Colin LeMahieu"
	date: "$Date: 2011-11-11 18:13:16 +0100 (ven., 11 nov. 2011) $"
	revision: "$Revision: 87787 $"
	quote: "What this country needs are more unemployed politicians. - Edward Langley"

class
	EC_POINT_F2M

inherit
	EC_POINT
		redefine
			x,
			y,
			opposite_value,
			twice_value,
			product_value,
			minus_value,
			plus_value
		end
	EC_CONSTANTS
		undefine
			is_equal
		end
	STANDARD_CURVES
		undefine
			is_equal
		end
	INTEGER_X_FACILITIES
		undefine
			is_equal
		end

create
	make_curve_x_y,
	make_infinity,
	make_from_bytes,
	make_sec_t113r1,
	make_sec_t113r2,
	make_sec_t131r1,
	make_sec_t131r2,
	make_sec_t163k1,
	make_sec_t163r1,
	make_sec_t163r2,
	make_sec_t193r1,
	make_sec_t193r2,
	make_sec_t233k1,
	make_sec_t233r1,
	make_sec_t239k1,
	make_sec_t283k1,
	make_sec_t283r1,
	make_sec_t409k1,
	make_sec_t409r1,
	make_sec_t571k1,
	make_sec_t571r1,
	make_k163,
	make_k233,
	make_k283,
	make_k409,
	make_k571,
	make_b163,
	make_b233,
	make_b283,
	make_b409,
	make_b571

feature
	make_infinity
		do
			set_infinity
		end

feature -- SEC points
	make_sec_t113r1
		do
			create x.make (sec_t113r1_gx)
			create y.make (sec_t113r1_gy)
		end

	make_sec_t113r2
		do
			create x.make (sec_t113r2_gx)
			create y.make (sec_t113r2_gy)
		end

	make_sec_t131r1
		do
			create x.make (sec_t131r1_gx)
			create y.make (sec_t131r1_gy)
		end

	make_sec_t131r2
		do
			create x.make (sec_t131r2_gx)
			create y.make (sec_t131r2_gy)
		end

	make_sec_t163k1
		do
			create x.make (sec_t163k1_gx)
			create y.make (sec_t163k1_gy)
		end

	make_sec_t163r1
		do
			create x.make (sec_t163r1_gx)
			create y.make (sec_t163r1_gy)
		end

	make_sec_t163r2
		do
			create x.make (sec_t163r2_gx)
			create y.make (sec_t163r2_gy)
		end

	make_sec_t193r1
		do
			create x.make (sec_t193r1_gx)
			create y.make (sec_t193r1_gy)
		end

	make_sec_t193r2
		do
			create x.make (sec_t193r2_gx)
			create y.make (sec_t193r2_gy)
		end

	make_sec_t233k1
		do
			create x.make (sec_t233k1_gx)
			create y.make (sec_t233k1_gy)
		end

	make_sec_t233r1
		do
			create x.make (sec_t233r1_gx)
			create y.make (sec_t233r1_gy)
		end

	make_sec_t239k1
		do
			create x.make (sec_t239k1_gx)
			create y.make (sec_t239k1_gy)
		end

	make_sec_t283k1
		do
			create x.make (sec_t283k1_gx)
			create y.make (sec_t283k1_gy)
		end

	make_sec_t283r1
		do
			create x.make (sec_t283r1_gx)
			create y.make (sec_t283r1_gy)
		end

	make_sec_t409k1
		do
			create x.make (sec_t409k1_gx)
			create y.make (sec_t409k1_gy)
		end

	make_sec_t409r1
		do
			create x.make (sec_t409r1_gx)
			create y.make (sec_t409r1_gy)
		end

	make_sec_t571k1
		do
			create x.make (sec_t571k1_gx)
			create y.make (sec_t571k1_gy)
		end

	make_sec_t571r1
		do
			create x.make (sec_t571r1_gx)
			create y.make (sec_t571r1_gy)
		end

feature -- FIPS points
	make_k163
		do
			create x.make (k163_gx)
			create y.make (k163_gy)
		end

	make_k233
		do
			create x.make (k233_gx)
			create y.make (k233_gy)
		end

	make_k283
		do
			create x.make (k283_gx)
			create y.make (k283_gy)
		end

	make_k409
		do
			create x.make (k409_gx)
			create y.make (k409_gy)
		end

	make_k571
		do
			create x.make (k571_gx)
			create y.make (k571_gy)
		end

	make_b163
		do
			create x.make (b163_gx)
			create y.make (b163_gy)
		end

	make_b233
		do
			create x.make (b233_gx)
			create y.make (b233_gy)
		end

	make_b283
		do
			create x.make (b283_gx)
			create y.make (b283_gy)
		end

	make_b409
		do
			create x.make (b409_gx)
			create y.make (b409_gy)
		end

	make_b571
		do
			create x.make (b571_gx)
			create y.make (b571_gy)
		end

	make_curve_x_y (x_a: EC_FIELD_ELEMENT_F2M; y_a: EC_FIELD_ELEMENT_F2M)
		do
			x := x_a
			y := y_a
		end

	make_from_bytes (bytes: SPECIAL[NATURAL_8]; curve: EC_CURVE_F2M)
		do
			decodepoint (bytes, curve)
		end

feature

	x: EC_FIELD_ELEMENT_F2M
	y: EC_FIELD_ELEMENT_F2M

	set_from_other (other: like Current)
		do
			x.copy (other.x)
			y.copy (other.y)
		end

feature -- Decode/encode

	set_infinity
		do
			create x.make (create {INTEGER_X}.default_create)
			create y.make (create {INTEGER_X}.default_create)
			infinity := True
		end

	decodePoint (source: SPECIAL [NATURAL_8] curve: EC_CURVE_F2M)
		require
			Source_too_small: source.capacity > 0
		local
			enc: SPECIAL [NATURAL_8]
		do
			create enc.make_filled (0, source.count - 1)
			enc.copy_data (source, 1, 0, enc.count)
			inspect
				source[0]
			when 0x02 then
				decodeCompressedPoint (enc, 0, curve)
			when 0x03 then
				decodeCompressedPoint (enc, 1, curve)
			when 0x04 then
				decodeUncompressedPoint (enc)
			end
		end

	decodeCompressedPoint (source: SPECIAL [NATURAL_8] ypBit: INTEGER curve: EC_CURVE_F2M)
		local
			xp: EC_FIELD_ELEMENT_F2M
			yp: EC_FIELD_ELEMENT_F2M
			i: INTEGER_32
			beta: EC_FIELD_ELEMENT_F2M
			z: EC_FIELD_ELEMENT_F2M
			oneEC: EC_FIELD_ELEMENT_F2M
			zBit: INTEGER
		do
			create xp.make (create {INTEGER_X}.make_from_bytes (source, source.lower, source.upper))
			if
				xp.x.is_zero
			then
				yp := curve.b
				from
					i := 0
				until
					i = curve.m - 1
				loop
					yp := yp.square_value (curve)
					i := i + 1
				end
			else
				beta := xp.plus_value (curve.a, curve).plus_value (curve.b.product_value (xp.square_value (curve).inverse_value (curve), curve), curve)
				--z := solveQuadraticEquation(beta)
				create z.make (create {INTEGER_X}.default_create)
				zBit := 0
				if
					z.x.bit_test (0)
				then
					zBit := 1
				end
				if
					zBit /= ypBit
				then
					create oneEC.make (ONE)
					z := z.plus_value (oneEC, curve)
				end
				yp := xp.product_value (z, curve)
			end
			x := xp
			y := yp
		end

	decodeUncompressedPoint (source: SPECIAL [NATURAL_8])
		require
			X_and_y_different_sizes: source.capacity \\ 2 = 0
		local
			xEnc: SPECIAL [NATURAL_8]
			yEnc: SPECIAL [NATURAL_8]
			x_mpz: INTEGER_X
			y_mpz: INTEGER_X
		do
			create xEnc.make_filled (0, source.count // 2)
			xEnc.copy_data (source, 0, 0, xEnc.count)
			create yEnc.make_filled (0, source.count // 2)
			yEnc.copy_data (source, source.count // 2, 0, yEnc.count)
			check -- Field elements should be same size
				xEnc.capacity = yEnc.capacity
			end
			create x_mpz.make_from_bytes (xEnc, xEnc.lower, xEnc.upper)
			create y_mpz.make_from_bytes (yEnc, yEnc.lower, yEnc.upper)
			create x.make (x_mpz)
			create y.make (y_mpz)
		end

	to_byte_array_uncompressed (curve: EC_CURVE_F2M): SPECIAL [NATURAL_8]
		local
			byteCount: INTEGER_32
			y_array: SPECIAL [NATURAL_8]
			x_array: SPECIAL [NATURAL_8]
			p0: SPECIAL [NATURAL_8]
		do
			bytecount := x.x.bytes
			x_array := x.x.as_bytes
			y_array := y.x.as_fixed_width_byte_array (byteCount)
			create p0.make_filled (0, byteCount + byteCount + 1)
			p0.put (0x04, 0)
			check
				x_array.capacity = y_array.capacity
			end
			p0.copy_data (x_array, 0, x_array.upper, 1)
			p0.copy_data (y_array, 0, y_array.upper, x_array.upper + 1)
			result := p0
		end

	to_byte_array_compressed (curve: EC_CURVE_F2M): SPECIAL [NATURAL_8]
		local
			byteCount: INTEGER_32
			x_array: SPECIAL [NATURAL_8]
			P0: SPECIAL [NATURAL_8]
		do
			x_array := x.x.as_bytes
			byteCount := x.x.bytes
			-- See X9.62 4.3.6 and 4.2.2
			create P0.make_filled (0, byteCount + 1)
			p0.put (0x02, 0)

			-- X9.62 4.2.2 and 4.3.6:
			-- if x = 0 then ypTilde := 0, else ypTilde is the rightmost
			-- bit of y * x^(-1)
			-- if ypTilde = 0, then PC := 02, else PC := 03
			-- Note: PC === PO[0]
			if
				(not (x.x.is_zero)) and ((y.product_value (x.inverse_value (curve), curve)).x.bit_test(0))
			then
				-- ypTilde = 1, hence PC = 03
				p0.put (0x03, 0)
			end
			p0.copy_data (x_array, 0, x_array.upper, 1)
			result := p0
		end

feature -- Implement ECPOINT

	plus_value (other: like Current; curve: EC_CURVE_F2M): EC_POINT_F2M
		do
			Result := Precursor (other, curve)
		end

	plus (other: like Current; curve: EC_CURVE_F2M)
		do
			if
				infinity
			then
				copy (other)
			elseif
				other.infinity
			then

			else
				add_not_infinity (other, curve)
			end
		end

	minus_value (other: like Current; curve: EC_CURVE_F2M): EC_POINT_F2M
		do
			Result := Precursor (other, curve)
		end

	minus (other: like Current; curve: EC_CURVE_F2M)
		do
			if
				other.infinity
			then
			else
				add_minus_b (other, curve)
			end
		end

	product_value (b: INTEGER_X; curve: EC_CURVE_F2M): EC_POINT_F2M
		do
			Result := Precursor (b, curve)
		end

	product (b: INTEGER_X; curve: EC_CURVE_F2M)
		local
			p: like Current
			q: like Current
			t: INTEGER_32
--			i: INTEGER_32
			special: SPECIAL [NATURAL_32]
			limb: NATURAL_32
			limb_position: INTEGER
			new_bit_position: INTEGER
			bit_position: INTEGER
		do
			p := Current
			create q.make_infinity
			t := b.bits
			from
				special := b.item
				limb := special [limb_position]
				limb_position := 0
				bit_position := 0
			until
				limb_position * 32 + bit_position >= t
			loop
				if limb.bit_test (bit_position) then
					q.plus (p, curve)
				end
				p.twice (curve)
				new_bit_position := (bit_position + 1) \\ 32
				if new_bit_position < bit_position then
					limb_position := limb_position + 1
					limb := special [limb_position]
				end
				bit_position := new_bit_position
			end
--			p := Current
--			create q.make_infinity
--			t := b.bits
--			from
--				i := 0
--			until
--				i = t
--			loop
--				if
--					b.bit_test (i)
--				then
--					q.plus (p, curve)
--				end
--				p.twice (curve)
--				i := i + 1
--			end
			copy (q)
		end

	twice_value (curve: EC_CURVE_F2M): EC_POINT_F2M
		do
			Result := Precursor (curve)
		end

	twice (curve: EC_CURVE_F2M)
		do
			if
				infinity
			then
			elseif
				x.x.is_zero
			then
				set_infinity
			else
				twice_not_infinity (curve)
			end
		end

	opposite_value (curve: EC_CURVE_F2M): EC_POINT_F2M
		do
			Result := Precursor (curve)
		end

	opposite (curve: EC_CURVE_F2M)
		do
			y.plus (x, curve)
		end

feature -- Implementation support features

	twice_not_infinity (curve: EC_CURVE_F2M)
		local
			lambda: EC_FIELD_ELEMENT_F2M
			x3: EC_FIELD_ELEMENT_F2M
			y3: EC_FIELD_ELEMENT_F2M
			one_element: EC_FIELD_ELEMENT_F2M
		do
			create one_element.make (one)
			lambda := y.quotient_value (x, curve)
			lambda.plus (x, curve)
			x3 := lambda.square_value (curve)
			x3.plus (lambda, curve)
			x3.plus (curve.a, curve)
			y3 := x.square_value (curve)
			lambda.plus (one_element, curve)
			lambda.product (x3, curve)
			y3.plus (lambda, curve)
			x := x3
			y := y3
		end

	add_minus_b (other: like Current curve: EC_CURVE_F2M)
		local
			minusB: like Current
		do
			create minusB.make_curve_x_y (other.x, other.x.plus_value (other.y, curve))
			plus (minusB, curve)
		end

	add_not_infinity (other: like Current; curve: EC_CURVE_F2M)
		do
			if
				x ~ other.x
			then
				if
					y ~ other.y
				then
					copy (twice_value (curve))
				else
					set_infinity
				end
			else
				add_normal (other, curve)
			end
		end

	add_normal (other: like Current; curve: EC_CURVE_F2M)
		local
			lambda: EC_FIELD_ELEMENT_F2M
			x3: EC_FIELD_ELEMENT_F2M
			y3: EC_FIELD_ELEMENT_F2M
		do
			lambda := (y.plus_value (other.y, curve)).quotient_value (x.plus_value (other.x, curve), curve)
			x3 := lambda.square_value (curve)
			x3 := x3.plus_value (lambda, curve).plus_value (x, curve).plus_value (other.x, curve).plus_value (curve.a, curve)
			y3 := ((lambda.product_value (x.plus_value (x3, curve), curve)).plus_value (x3, curve)).plus_value (y, curve)
			x := x3
			y := y3
		end
end
