Class: RingSig::Hasher
- Inherits:
-
Object
- Object
- RingSig::Hasher
- Defined in:
- lib/ring_sig/hasher.rb
Overview
A customized hasher specifically for Ring Signatures.
Instance Attribute Summary collapse
- #algorithm ⇒ #digest readonly
- #group ⇒ ECDSA::Group readonly
Instance Method Summary collapse
-
#==(other) ⇒ Boolean
True if the hashers are equal.
-
#hash_array(array) ⇒ Integer
Hashes an array.
-
#hash_point(point) ⇒ ECDSA::Point
Hashes a point to another point.
-
#hash_string(s) ⇒ Integer
Uniformly hashes a string to a number between 0 and the group's order.
-
#initialize(group, algorithm) ⇒ Hasher
constructor
Creates a new instance of Hasher.
-
#shuffle(array, seed) ⇒ Array
Shuffles an array in a deterministic manner.
Constructor Details
#initialize(group, algorithm) ⇒ Hasher
The byte-length of the group's order and the digest method must match, or else signatures generated from this hasher will leak the position of the true signer.
Creates a new instance of RingSig::Hasher.
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/ring_sig/hasher.rb', line 18 def initialize(group, algorithm) @group = group @algorithm = algorithm algorithm_byte_length = algorithm.digest('a').size if group.byte_length != algorithm_byte_length raise ArgumentError, "Group's byte length (#{group.byte_length}), does not match hash algorithm's byte length (#{algorithm_byte_length})" end digest_max = 2 ** (algorithm_byte_length * 8) - 1 if digest_max < group.order raise ArgumentError, "Invalid ECDSA group. Group's order must be less than the hash algorithm's maximum value" end @hash_cieling = digest_max - digest_max % group.order end |
Instance Attribute Details
#algorithm ⇒ #digest (readonly)
8 9 10 |
# File 'lib/ring_sig/hasher.rb', line 8 def algorithm @algorithm end |
#group ⇒ ECDSA::Group (readonly)
5 6 7 |
# File 'lib/ring_sig/hasher.rb', line 5 def group @group end |
Instance Method Details
#==(other) ⇒ Boolean
Returns true if the hashers are equal.
96 97 98 |
# File 'lib/ring_sig/hasher.rb', line 96 def ==(other) group == other.group && algorithm == other.algorithm end |
#hash_array(array) ⇒ Integer
Hashes an array. Converts the Array to an OpenSSL::ASN1::Sequence der string, and then hashes that string.
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/ring_sig/hasher.rb', line 54 def hash_array(array) array = array.map do |e| case e when String OpenSSL::ASN1::UTF8String.new(e) when Integer OpenSSL::ASN1::Integer.new(e) when ECDSA::Point OpenSSL::ASN1::OctetString.new(ECDSA::Format::PointOctetString.encode(e, compression: true)) else raise ArgumentError, "Unsupported type: #{p.inspect}" end end hash_string(OpenSSL::ASN1::Sequence.new(array).to_der) end |
#hash_point(point) ⇒ ECDSA::Point
Hashes a point to another point.
76 77 78 |
# File 'lib/ring_sig/hasher.rb', line 76 def hash_point(point) @group.generator * hash_array(point.coords) end |
#hash_string(s) ⇒ Integer
Uniformly hashes a string to a number between 0 and the group's order.
39 40 41 42 43 44 45 46 47 |
# File 'lib/ring_sig/hasher.rb', line 39 def hash_string(s) n = nil loop do s = algorithm.digest(s) n = s.unpack('H*').first.to_i(16) break if n < @hash_cieling end n % group.order end |
#shuffle(array, seed) ⇒ Array
Shuffles an array in a deterministic manner.
86 87 88 89 90 91 92 93 |
# File 'lib/ring_sig/hasher.rb', line 86 def shuffle(array, seed) seed_array = [seed, 0] (array.size - 1).downto(1) do |i| r = next_rand(i + 1, seed_array) array[i], array[r] = array[r], array[i] end array end |