openssl
openssl copied to clipboard
`OpenSSL::PKey::EC::Point` should be able to get and set affine coordinates
It is possible using a little magic to create a point with a raw x and y:
def self.from_compressed_point(group, x, is_even)
x_value = x.to_s(2).rjust(32, "\x00")
prefix = is_even ? "\x02" : "\x03"
encoded = OpenSSL::BN.new [ prefix, x_value ].join, 2
OpenSSL::PKey::EC::Point.new(group, encoded)
end
One can similarly use some magic to get uncompressed points and turn them into two OpenSSL::BN instances
It would be better if we supported this without using compressed point form magic, like so (RBS signature with hypothetical overload):
class OpenSSL::PKey::EC::Point
# Since the OpenSSL operation returns both
def affine_coordinates -> [ OpenSSL::BN, OpenSSL::BN ]
# Convenance methods for above
attr_reader :x, :y -> OpenSSL::BN
# Choice 1 - Using Bool for Y
def initialize : (group: OpenSSL::PKey::EC::Group, x: OpenSSL::BN, even: Boolean) -> OpenSSL::PKey::EC::Point
# Choice 2 - Using a symbol for Y
def initialize : (group: OpenSSL::PKey::EC::Group, x: OpenSSL::BN, y:[ :even, :odd ]) -> OpenSSL::PKey::EC::Point
# Using X and Y directly
def initialize : (group: OpenSSL::PKey::EC::Group, x: OpenSSL::BN, y: OpenSSL::BN) -> OpenSSL::PKey::EC::Point
end
I've intentionally omitted mutating the X and Y of a point after creation. Because all of these have a different aridity they will not conflict. Similarly adding Jacobian would create an aridity == 4.
The big question is for choice 1 or 2 when creating an X and which Y value.
Doh - maybe its best to have it be "odd" as the boolean. Since 0 == false == even and 1 == true == odd?
Yes, this is a good feature to have.
# Choice 1 - Using Bool for Y def initialize : (group: OpenSSL::PKey::EC::Group, x: OpenSSL::BN, even: Boolean) -> OpenSSL::PKey::EC::Point # Choice 2 - Using a symbol for Y def initialize : (group: OpenSSL::PKey::EC::Group, x: OpenSSL::BN, y:[ :even, :odd ]) -> OpenSSL::PKey::EC::Point
SEC 1 refers to the compressed value as ỹP = 0
or ỹP = 1
and OpenSSL's man page calls it y_bit
, seemingly because it indicates the different property in GF(p) group vs in GF(2m). I got the feeling that the Ruby interface also should take the integer 0 or 1, but I'm no expert.
In any case, I'd like to have this as a separate method from EC::Point.new
(something like from_compressed_coordinates
), since determining what the argument means by checking type isn't very Ruby-like.
I got the feeling that the Ruby interface also should take the integer 0 or 1, but I'm no expert.
I'd like to avoid Integer
here - because using :even
and :odd
prevent accidents where one gets a point at (x, 1) where it was intending to resolve compression. So even if its a separate from_compressed_coordinates(x : BN, y_bit: Symbol)
and a from_coordinates(x: BN, y: BN)
as class methods I'm good with it. These can just be helpers to encode the proper prefix and call the usual initializer to reduce the "magic" being done in the ruby bindings...
Operation becomes: For Uncompressed Coordinates: Convert X and Y to byte string Widen X and Y BN to the degree Call new with "\x04" + X + Y
For Compressed Coordinates Convert X to byte string Widen X to degree Prefix with "\x02" or "\x03" and append X Call new with above
I found the bit is sometimes called odd or even in a GF(p) group's context, but I couldn't be sure if the word choice is appropriate in a GF(2m) group's context, too. The encoding seems more complex there, it's not taken directly from the right-most bit of y
value but yx^-1
.