note
	description: "Objects that ..."
	author: "Colin LeMahieu"
	date: "$Date: 2011-11-11 18:13:16 +0100 (ven., 11 nov. 2011) $"
	revision: "$Revision: 87787 $"
	quote: "The power to tax is the power to destroy. - John Marshall"

class
	EC_FIELD_ELEMENT_F2M

inherit
	EC_FIELD_ELEMENT
		redefine
			is_equal,
			plus_value,
			minus_value,
			product_value,
			quotient_value,
			opposite_value,
			square_value,
			inverse_value
		end

	F2M_REPRESENTATIONS
		undefine
			is_equal,
			copy
		end

	INTEGER_X_FACILITIES
		undefine
			is_equal,
			copy
		end

	LIMB_MANIPULATION
		undefine
			is_equal,
			copy
		end

	SPECIAL_UTILITY
		undefine
			is_equal,
			copy
		end

create
	make

convert
	make ({INTEGER_X})

feature {NONE}

	make (x_a: INTEGER_X)
		require
			non_negative_x: not x_a.is_negative
		do
			x := x_a
		end

feature -- Field element components

	multZModF (a: INTEGER_X; m_limb_position: INTEGER m_bit_position: INTEGER k1_limb_position: INTEGER k1_bit_position: INTEGER)
		require
			a.is_positive
		local
			special: SPECIAL [NATURAL_32]
			limb: NATURAL_32
		do
			a.bit_shift_left (1)
			special := a.item
			limb := special [m_limb_position]
			if
				limb.bit_test (m_bit_position)
			then
				special [m_limb_position] := limb.set_bit (False, m_bit_position)
				special [0] := special [0].bit_xor (1)
				special [k1_limb_position] := special [k1_limb_position].bit_xor ((1).to_natural_32 |<< k1_bit_position)
			end
		ensure
			a.is_positive
		end


	multZModF_p (a: INTEGER_X; m_limb_position: INTEGER m_bit_position: INTEGER k1_limb_position: INTEGER k1_bit_position: INTEGER k2_limb_position: INTEGER k2_bit_position: INTEGER k3_limb_position: INTEGER k3_bit_position: INTEGER)
		require
			a.is_positive
		local
			special: SPECIAL [NATURAL_32]
			limb: NATURAL_32
		do
			a.bit_shift_left (1)
			special := a.item
			limb := special [m_limb_position]
			if
				limb.bit_test (m_bit_position)
			then
				special [m_limb_position] := limb.set_bit (False, m_bit_position)
				special [0] := special [0].bit_xor (1)
				special [k1_limb_position] := special [k1_limb_position].bit_xor ((1).to_natural_32 |<< k1_bit_position)
				special [k2_limb_position] := special [k2_limb_position].bit_xor ((1).to_natural_32 |<< k2_bit_position)
				special [k3_limb_position] := special [k3_limb_position].bit_xor ((1).to_natural_32 |<< k3_bit_position)
			end
		ensure
			a.is_positive
		end

feature

	encoded_field_size (curve: EC_CURVE_F2M): INTEGER_32
			--
		obsolete
			"Needs implementation"
		do

		end

feature -- Implementing features of ECFIELDELEMENT

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

	plus (other: like Current; curve: EC_CURVE_F2M)
		do
			x.bit_xor (other.x)
		end

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

	minus (other: like Current; curve: EC_CURVE_F2M)
		do
			plus (other, curve)
		end

	product_value (b: like Current; curve: EC_CURVE_F2M): EC_FIELD_ELEMENT_F2M
		do
			Result := Precursor (b, curve)
		end

	product (b: like Current; curve: EC_CURVE_F2M)
		local
			m: INTEGER
			m_bit_position: INTEGER
			m_limb_position: INTEGER
			k1_bit_position: INTEGER
			k1_limb_position: INTEGER
			k2_bit_position: INTEGER
			k2_limb_position: INTEGER
			k3_bit_position: INTEGER
			k3_limb_position: INTEGER
			bz: INTEGER_X
			cz: INTEGER_X
			special: SPECIAL [NATURAL_32]
			limb: NATURAL_32
			limb_position: INTEGER
			bit_position: INTEGER
			new_bit_position: INTEGER
		do
			m := curve.m
			m_limb_position := bit_index_to_limb_index (m)
			m_bit_position := m \\ limb_bits
			k1_limb_position := bit_index_to_limb_index (curve.k1)
			k1_bit_position := curve.k1 \\ limb_bits
			k2_limb_position := bit_index_to_limb_index (curve.k2)
			k2_bit_position := curve.k2 \\ limb_bits
			k3_limb_position := bit_index_to_limb_index (curve.k3)
			k3_bit_position := curve.k3 \\ limb_bits
			create bz.make_bits (m + m)
			bz.copy (b.x)
			limb_position := 0
			bit_position := 0
			special := x.item
			x.resize (bits_to_limbs (m))
			limb := special [limb_position]
			create cz.make_bits (m + m)
			from
				bit_position := 0
			until
				limb_position * limb_bits + bit_position >= m
			loop
				if
					limb.bit_test (bit_position)
				then
					cz.bit_xor (bz)
				end
				new_bit_position := (bit_position + 1) \\ limb_bits
				if new_bit_position < bit_position then
					limb_position := limb_position + 1
					limb := special [limb_position]
				end
				bit_position := new_bit_position
				if curve.representation = PPB then
					multZmodF_p (bz, m_limb_position, m_bit_position, k1_limb_position, k1_bit_position, k2_limb_position, k2_bit_position, k3_limb_position, k3_bit_position)
				else
					multZmodF (bz, m_limb_position, m_bit_position, k1_limb_position, k1_bit_position)
				end
			end
			x := cz
		end

	quotient_value (other: like Current; curve: EC_CURVE_F2M): EC_FIELD_ELEMENT_F2M
		do
			Result := Precursor (other, curve)
		end

	quotient (other: like Current; curve: EC_CURVE_F2M)
		local
			bInv: like Current
		do
			bInv := other.inverse_value (curve)
			product (bInv, curve)
		end

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

	opposite (curve: EC_CURVE_F2M)
		do
			do_nothing
		end

	square_value (curve: EC_CURVE_F2M): EC_FIELD_ELEMENT_F2M
		do
			Result := Precursor (curve)
		end

	square (curve: EC_CURVE_F2M)
		local
			i: INTEGER_32
			limb_position: INTEGER
			bit_position: INTEGER
			new_bit_position: INTEGER
			square_limb_position: INTEGER
			square_bit_position: INTEGER
			limb: NATURAL_32
			square_limb: NATURAL_32
			special: SPECIAL [NATURAL_32]
		do
			from
				i := curve.m
				x.resize (bits_to_limbs (i + i))
				special := x.item
				limb_position := bit_index_to_limb_index (i)
				bit_position := i \\ limb_bits
				square_limb_position := bit_index_to_limb_index (i + i)
				square_bit_position := (i + i) \\ limb_bits
				limb := special [limb_position]
				square_limb := special [square_limb_position]
			invariant
				i = limb_position * limb_bits + bit_position
			until
				i < 0
			loop
				if
					limb.bit_test (bit_position)
				then
--					x.set_bit (True, i + i)
					square_limb := square_limb.set_bit (True, square_bit_position)
				else
--					x.set_bit (False, i + i)
					square_limb := square_limb.set_bit (False, square_bit_position)
				end
--				x.set_bit (False, i + i + 1)
				square_limb := square_limb.set_bit (False, square_bit_position + 1)
				new_bit_position := bit_position - 1
				if new_bit_position < 0 and limb_position > 0 then
					new_bit_position := new_bit_position + limb_bits
					limb_position := limb_position - 1
					limb := special [limb_position]
				end
				bit_position := new_bit_position
				new_bit_position := square_bit_position - 2
				if new_bit_position < 0 and square_limb_position > 0 then
					new_bit_position := new_bit_position + limb_bits
					special [square_limb_position] := square_limb
					square_limb_position := square_limb_position - 1
					square_limb := special [square_limb_position]
				end
				square_bit_position := new_bit_position
				i := i - 1
			variant
				i + 3
			end
			if square_bit_position /= limb_bits - 2 then
				special [square_limb_position] := square_limb
			else
				do_nothing
			end
			reduce (x, curve)
			x.count := x.normalize (special, 0, bits_to_limbs (curve.m))
		end

	reduce (in: INTEGER_X; curve: EC_CURVE_F2M)
		local
			m: INTEGER
			i: INTEGER
			k1: INTEGER
			k1_limb_position: INTEGER
			k1_limb_diff: NATURAL_32
			k1_bit_position: INTEGER
			k2: INTEGER
			k2_limb_position: INTEGER
			k2_limb_diff: NATURAL_32
			k2_bit_position: INTEGER
			k3: INTEGER
			k3_limb_position: INTEGER
			k3_limb_diff: NATURAL_32
			k3_bit_position: INTEGER
			low_limb_position: INTEGER
			low_limb_diff: NATURAL_32
			low_bit_position: INTEGER
			special: SPECIAL [NATURAL_32]
			limb: NATURAL_32
			limb_diff: NATURAL_32
			limb_position: INTEGER
			bit_position: INTEGER
			new_bit_position: INTEGER
		do
			m := curve.m
			k1 := curve.k1
			k2 := curve.k2
			k3 := curve.k3
			special := in.item
			from
				i := m + m - 1
				limb_position := bit_index_to_limb_index (i)
				low_limb_position := bit_index_to_limb_index (i - m)
				k1_limb_position := bit_index_to_limb_index (k1 + i - m)
				bit_position := i \\ limb_bits
				low_bit_position := (i - m) \\ limb_bits
				k1_bit_position := (k1 + i - m) \\ limb_bits
				if curve.representation = PPB then
					k2_limb_position := bit_index_to_limb_index (k2 + i - m)
					k3_limb_position := bit_index_to_limb_index (k3 + i - m)
					k2_bit_position := (k2 + i - m) \\ limb_bits
					k3_bit_position := (k3 + i - m) \\ limb_bits
				end
				limb := special [limb_position]
			invariant
				i = limb_position * limb_bits + bit_position
			until
				i < m
			loop
				if
					limb.bit_test (bit_position)
				then
					limb_diff := limb_diff.set_bit (True, bit_position)
					low_limb_diff := low_limb_diff.set_bit (True, low_bit_position)
					k1_limb_diff := k1_limb_diff.set_bit (True, k1_bit_position)
					if
						curve.representation = PPB
					then
						k2_limb_diff := k2_limb_diff.set_bit (True, k2_bit_position)
						k3_limb_diff := k3_limb_diff.set_bit (True, k3_bit_position)
					end
				end
				new_bit_position := bit_position - 1
				if new_bit_position < 0 then
					new_bit_position := new_bit_position + limb_bits
					special [limb_position] := special [limb_position].bit_xor (limb_diff)
					limb_position := limb_position - 1
					limb := special [limb_position]
					limb_diff := 0
				end
				bit_position := new_bit_position
				new_bit_position := low_bit_position - 1
				if new_bit_position < 0 then
					new_bit_position := new_bit_position + limb_bits
					special [low_limb_position] := special [low_limb_position].bit_xor (low_limb_diff)
					low_limb_position := low_limb_position - 1
					low_limb_diff := 0
				end
				low_bit_position := new_bit_position
				new_bit_position := k1_bit_position - 1
				if new_bit_position < 0 then
					new_bit_position := new_bit_position + limb_bits
					special [k1_limb_position] := special [k1_limb_position].bit_xor (k1_limb_diff)
					k1_limb_position := k1_limb_position - 1
					k1_limb_diff := 0
				end
				k1_bit_position := new_bit_position
				if curve.representation = PPB then
					new_bit_position := k2_bit_position - 1
					if new_bit_position < 0 then
						new_bit_position := new_bit_position + limb_bits
						special [k2_limb_position] := special [k2_limb_position].bit_xor (k2_limb_diff)
						k2_limb_position := k2_limb_position - 1
						k2_limb_diff := 0
					end
					k2_bit_position := new_bit_position
					new_bit_position := k3_bit_position - 1
					if new_bit_position < 0 then
						new_bit_position := new_bit_position + limb_bits
						special [k3_limb_position] := special [k3_limb_position].bit_xor (k3_limb_diff)
						k3_limb_position := k3_limb_position - 1
						k3_limb_diff := 0
					end
					k3_bit_position := new_bit_position
				end
				i := i - 1
			end
			if bit_position /= limb_bits - 1 then
				special [limb_position] := special [limb_position].bit_xor (limb_diff)
			end
			if low_bit_position /= limb_bits - 1 then
				special [low_limb_position] := special [low_limb_position].bit_xor (low_limb_diff)
			end
			if k1_bit_position /= limb_bits - 1 then
				special [k1_limb_position] := special [k1_limb_position].bit_xor (k1_limb_diff)
			end
			if curve.representation = PPB then
				if k2_bit_position /= limb_bits - 1 then
					special [k2_limb_position] := special [k2_limb_position].bit_xor (k2_limb_diff)
				end
				if k3_bit_position /= limb_bits - 1 then
					special [k3_limb_position] := special [k3_limb_position].bit_xor (k3_limb_diff)
				end
			end
			in.count := in.normalize (special, 0, in.count)
		end

	inverse_value (curve: EC_CURVE_F2M): EC_FIELD_ELEMENT_F2M
		do
			Result := Precursor (curve)
		end

	inverse (curve: EC_CURVE_F2M)
		local
			uz: INTEGER_X
			vz: INTEGER_X
--			g1z: INTEGER_X
--			g2z: INTEGER_X
--			j: INTEGER_32
--			tmp_int: INTEGER_X
			m: INTEGER
--			uz_bits: INTEGER
--			vz_bits: INTEGER
--			tmp_int2: INTEGER
--			uz_old: INTEGER_X
--			gz_old: INTEGER_X
		do
			m := curve.m
			create uz.make_bits (m + m)
			uz.copy (x)
			create vz.make_bits (m + m)
			vz.set_bit (True, m)
			vz.set_bit (True, 0)
			vz.set_bit (True, curve.k1)
			if
				curve.representation = PPB
			then
				vz.set_bit (True, curve.k2)
				vz.set_bit (True, curve.k3)
			end
			vz.count := normalize (vz.item, 0, bits_to_limbs (m))

			x.invert_gf (vz)
--			create g1z.make_bits (m + m)
--			g1z.set_from_integer (1)
--			create g2z.make_bits (m + m)
--			from
--			until
--				uz.is_zero
--			loop
--				uz_bits := uz.bits
--				vz_bits := vz.bits
--				if
--					uz_bits < vz_bits
--				then
--					tmp_int := uz
--					uz := vz
--					vz := tmp_int
--					tmp_int := g1z
--					g1z := g2z
--					g2z := tmp_int
--					tmp_int2 := uz_bits
--					uz_bits := vz_bits
--					vz_bits := tmp_int2
--				end
--				if uz_bits /= vz_bits then
--					j := uz_bits - vz_bits
----					vz.bit_shift_left (j)
----					uz_old := uz.bit_xor_value (vz)
----					vz.bit_shift_right (j)
----					g2z.bit_shift_left (j)
----					gz_old := g1z.bit_xor_value (g2z)
----					g2z.bit_shift_right (j)
--					uz.bit_xor_left_shift (vz, j)
--					g1z.bit_xor_left_shift (g2z, j)
--				else
--					uz.bit_xor (vz)
--					g1z.bit_xor (g2z)
--				end
--			end
--			x := g2z
		end

	sqrt (curve: EC_CURVE_F2M): like Current
			-- Not implemented
		do
			create Result.make (create {INTEGER_X}.default_create)
		end

	is_equal (other: like Current): BOOLEAN
		do
			Result := x ~ other.x
		end

end
