Module: ECDSA
- Defined in:
- lib/ecdsa.rb,
lib/ecdsa/sign.rb,
lib/ecdsa/group.rb,
lib/ecdsa/point.rb,
lib/ecdsa/verify.rb,
lib/ecdsa/version.rb,
lib/ecdsa/signature.rb,
lib/ecdsa/prime_field.rb,
lib/ecdsa/group/nistp192.rb,
lib/ecdsa/group/nistp224.rb,
lib/ecdsa/group/nistp256.rb,
lib/ecdsa/group/nistp384.rb,
lib/ecdsa/group/nistp521.rb,
lib/ecdsa/group/secp112r1.rb,
lib/ecdsa/group/secp112r2.rb,
lib/ecdsa/group/secp128r1.rb,
lib/ecdsa/group/secp128r2.rb,
lib/ecdsa/group/secp160k1.rb,
lib/ecdsa/group/secp160r1.rb,
lib/ecdsa/group/secp160r2.rb,
lib/ecdsa/group/secp192k1.rb,
lib/ecdsa/group/secp192r1.rb,
lib/ecdsa/group/secp224k1.rb,
lib/ecdsa/group/secp224r1.rb,
lib/ecdsa/group/secp256k1.rb,
lib/ecdsa/group/secp256r1.rb,
lib/ecdsa/group/secp384r1.rb,
lib/ecdsa/group/secp521r1.rb,
lib/ecdsa/recover_public_key.rb,
lib/ecdsa/format/decode_error.rb,
lib/ecdsa/format/point_octet_string.rb,
lib/ecdsa/format/integer_octet_string.rb,
lib/ecdsa/format/signature_der_string.rb,
lib/ecdsa/format/field_element_octet_string.rb
Overview
Defined Under Namespace
Modules: Format Classes: Group, InvalidSignatureError, Point, PrimeField, SZeroError, Signature
Constant Summary collapse
- VERSION =
'1.2.0'
Class Method Summary collapse
-
.bit_length(integer) ⇒ Object
This method is NOT part of the public API of the ECDSA gem.
-
.byte_length(integer) ⇒ Object
This method is NOT part of the public API of the ECDSA gem.
-
.check_signature!(public_key, digest, signature) ⇒ Object
Verifies the given Signature and raises an InvalidSignatureError if it is invalid.
-
.normalize_digest(digest, bit_length) ⇒ Object
This method is NOT part of the public API of the ECDSA gem.
-
.recover_public_key(group, digest, signature) ⇒ Object
Recovers the set of possible public keys from a Signature and the digest that it signs.
-
.sign(group, private_key, digest, temporary_key) ⇒ Signature or nil
Produces an ECDSA signature.
-
.valid_signature?(public_key, digest, signature) ⇒ Boolean
Verifies the given Signature and returns true if it is valid.
Class Method Details
.bit_length(integer) ⇒ Object
This method is NOT part of the public API of the ECDSA gem.
22 23 24 25 26 27 28 29 |
# File 'lib/ecdsa.rb', line 22 def self.bit_length(integer) length = 0 while integer > 0 length += 1 integer >>= 1 end length end |
.byte_length(integer) ⇒ Object
This method is NOT part of the public API of the ECDSA gem.
12 13 14 15 16 17 18 19 |
# File 'lib/ecdsa.rb', line 12 def self.byte_length(integer) length = 0 while integer > 0 length += 1 integer >>= 8 end length end |
.check_signature!(public_key, digest, signature) ⇒ Object
Verifies the given Signature and raises an InvalidSignatureError if it is invalid.
This algorithm comes from Section 4.1.4 of [SEC1](www.secg.org/collateral/sec1_final.pdf).
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/ecdsa/verify.rb', line 29 def self.check_signature!(public_key, digest, signature) group = public_key.group field = group.field # Step 1: r and s must be in the field and non-zero raise InvalidSignatureError, 'Invalid signature: r is not in the field.' if !field.include?(signature.r) raise InvalidSignatureError, 'Invalid signature: s is not in the field.' if !field.include?(signature.s) raise InvalidSignatureError, 'Invalid signature: r is zero.' if signature.r.zero? raise InvalidSignatureError, 'Invalid signature: s is zero.' if signature.s.zero? # Step 2 was already performed when the digest of the message was computed. # Step 3: Convert octet string to number and take leftmost bits. e = normalize_digest(digest, group.bit_length) # Step 4 point_field = PrimeField.new(group.order) s_inverted = point_field.inverse(signature.s) u1 = point_field.mod(e * s_inverted) u2 = point_field.mod(signature.r * s_inverted) # Step 5 r = group.generator.multiply_by_scalar(u1).add_to_point public_key.multiply_by_scalar(u2) raise InvalidSignatureError, 'Invalid signature: r is infinity in step 5.' if r.infinity? # Steps 6 and 7 v = point_field.mod r.x # Step 8 raise InvalidSignatureError, 'Invalid signature: v does not equal r.' if v != signature.r true end |
.normalize_digest(digest, bit_length) ⇒ Object
This method is NOT part of the public API of the ECDSA gem.
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/ecdsa.rb', line 32 def self.normalize_digest(digest, bit_length) if digest.is_a?(String) digest = digest.dup.force_encoding('BINARY') digest_bit_length = digest.size * 8 num = Format::IntegerOctetString.decode(digest) if digest_bit_length <= bit_length num else num >> (digest_bit_length - bit_length) end elsif digest.is_a?(Integer) digest else raise ArgumentError, 'Digest must be a string or integer.' end end |
.recover_public_key(group, digest, signature) ⇒ Object
Recovers the set of possible public keys from a Signature and the digest that it signs.
If you do not pass a block to ‘recover_public_key` then it returns an Enumerator that will lazily find more public keys when needed. If you are going to iterate through the enumerator more than once, you should probably convert it to an array first with `to_a` to save CPU time.
If you pass a block, it will yield the public keys to the block one at a time as it finds them.
This is better than just returning an array of all possibilities, because it allows the caller to stop the algorithm when the desired public key has been found, saving CPU time.
This algorithm comes from Section 4.1.6 of [SEC1 2.0](www.secg.org/download/aid-780/sec1-v2.pdf)
22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/ecdsa/recover_public_key.rb', line 22 def self.recover_public_key(group, digest, signature) return enum_for(:recover_public_key, group, digest, signature) if !block_given? digest = normalize_digest(digest, group.bit_length) each_possible_temporary_public_key(group, digest, signature) do |point| yield calculate_public_key(group, digest, signature, point) end nil end |
.sign(group, private_key, digest, temporary_key) ⇒ Signature or nil
Produces an ECDSA signature.
This algorithm comes from section 4.1.3 of [SEC1](www.secg.org/collateral/sec1_final.pdf).
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/ecdsa/sign.rb', line 25 def self.sign(group, private_key, digest, temporary_key) # Second part of step 1: Select ephemeral elliptic curve key pair # temporary_key was already selected for us by the caller r_point = group.new_point temporary_key # Steps 2 and 3 point_field = PrimeField.new(group.order) r = point_field.mod(r_point.x) return nil if r.zero? # Step 4, calculating the hash, was already performed by the caller. # Step 5 e = normalize_digest(digest, group.bit_length) # Step 6 s = point_field.mod(point_field.inverse(temporary_key) * (e + r * private_key)) return nil if s.zero? Signature.new r, s end |
.valid_signature?(public_key, digest, signature) ⇒ Boolean
Verifies the given Signature and returns true if it is valid.
This algorithm comes from Section 4.1.4 of [SEC1](www.secg.org/collateral/sec1_final.pdf).
14 15 16 17 18 |
# File 'lib/ecdsa/verify.rb', line 14 def self.valid_signature?(public_key, digest, signature) check_signature! public_key, digest, signature rescue InvalidSignatureError false end |