Skip to content
This repository has been archived by the owner on Aug 28, 2019. It is now read-only.

Commit

Permalink
Replace broken backports gem Bignum#bit_length with custom monkey-pat…
Browse files Browse the repository at this point in the history
…ch for MRI < 2.1

I filed the following bug with backports gem:

marcandre/backports#95

Added some tests to cover this function, but they will only be using
the backport version if the current Ruby runtime doesn't support #bit_length

Also, backports gem need require => false in Gemfile so *all* backports
don't get loaded which we don't want. That is why I had to also bring in
Range#bsearch manually. So now we are not using the backports gem at all.
  • Loading branch information
grempe committed Jul 8, 2015
1 parent 9570369 commit 68d44ce
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 7 deletions.
86 changes: 86 additions & 0 deletions lib/backports/bit_length.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Backport support for Bignum#bit_length and Fixnum#bit_length which were added in Ruby 2.1
# See : http://globaldev.co.uk/2014/05/ruby-2-1-in-detail/
# See : https://github.com/marcandre/backports
#
# NOTE: Had to add this as a monkey patch here since Bignum#bit_length is broken
# in the backports gem. Bug filed:
# https://github.com/marcandre/backports/issues/95

# Supports #bit_length
# a direct copy from backports gem
unless Range.method_defined? :bsearch
class Range
def bsearch
return to_enum(:bsearch) unless block_given?
from = self.begin
to = self.end
unless from.is_a?(Numeric) && to.is_a?(Numeric)
raise TypeError, "can't do binary search for #{from.class}"
end

midpoint = nil
if from.is_a?(Integer) && to.is_a?(Integer)
convert = Proc.new{ midpoint }
else
map = Proc.new do |pk, unpk, nb|
result, = [nb.abs].pack(pk).unpack(unpk)
nb < 0 ? -result : result
end
from = map['D', 'q', to.to_f]
to = map['D', 'q', to.to_f]
convert = Proc.new{ map['q', 'D', midpoint] }
end
to -= 1 if exclude_end?
satisfied = nil
while from <= to do
midpoint = (from + to).div(2)
result = yield(cur = convert.call)
case result
when Numeric
return cur if result == 0
result = result < 0
when true
satisfied = cur
when nil, false
# nothing to do
else
raise TypeError, "wrong argument type #{result.class} (must be numeric, true, false or nil)"
end

if result
to = midpoint - 1
else
from = midpoint + 1
end
end
satisfied
end
end
end

# For MRI < 2.1, and other Rubies
# A direct copy from backports gem
unless Fixnum.method_defined? :bit_length
# require 'backports/2.0.0/range/bsearch'
class Fixnum
def bit_length
n = if self >= 0
self + 1
else
-self
end
(0...8 * size).bsearch{|i| n <= (1 << i) }
end
end
end

# For MRI < 2.1, and other Rubies
# My own temporary implementation of bit_length. Until the bug report
# above is resolved.
unless Bignum.method_defined? :bit_length
class Bignum
def bit_length
(self).abs.to_s(2).length
end
end
end
8 changes: 2 additions & 6 deletions lib/secretsharing.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.

# Backport support for Bignum#bit_length and Fixnum#bit_length which were added in Ruby 2.1
# See : http://globaldev.co.uk/2014/05/ruby-2-1-in-detail/
# See : https://github.com/marcandre/backports
require 'backports/1.9.1/kernel/require_relative'
require 'backports/2.1.0/bignum/bit_length'
require 'backports/2.1.0/fixnum/bit_length'
# custom local monkey-patches
require 'backports/bit_length'

require 'rbnacl/libsodium'
require 'rbnacl'
Expand Down
1 change: 0 additions & 1 deletion secretsharing.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ Gem::Specification.new do |s|
s.add_dependency 'rbnacl', '~> 3.2.0'
s.add_dependency 'highline', '~> 1.7.2'
s.add_dependency 'multi_json', '~> 1.11.2'
s.add_dependency 'backports', '~> 3.6.4'

s.add_development_dependency 'mocha'
s.add_development_dependency 'minitest'
Expand Down
57 changes: 57 additions & 0 deletions spec/backport_bit_length_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# -*- encoding: utf-8 -*-

# Copyright 2011-2015 Glenn Rempe

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

# http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require File.expand_path('../spec_helper', __FILE__)

# NOTE : these backport tests are only meaninful when run on
# a Ruby runtime that doesn't natively support Bignum.bit_length
describe 'Bignum#bit_length' do
include SecretSharing::Shamir

it 'will return the expected bit_length for multiples of 256' do
[256, 512, 768, 1024].each do |i|
r = get_random_number_with_bitlength(i)
r.bit_length.must_equal(i)
end
end

it 'will return the expected bit_length for multiples of 256 + 1' do
[257, 513, 769, 1025].each do |i|
r = get_random_number_with_bitlength(i)
r.bit_length.must_equal(i)
end
end
end

# NOTE : these backport tests are only meaninful when run on
# a Ruby runtime that doesn't natively support Fixnum.bit_length
describe 'Fixnum#bit_length' do
include SecretSharing::Shamir

it 'will return the expected bit_length for multiples of 8' do
[1, 8, 16, 24, 32].each do |i|
r = get_random_number_with_bitlength(i)
r.bit_length.must_equal(i)
end
end

it 'will return the expected bit_length for multiples of 8 + 1' do
[2, 9, 17, 25, 33].each do |i|
r = get_random_number_with_bitlength(i)
r.bit_length.must_equal(i)
end
end
end

0 comments on commit 68d44ce

Please sign in to comment.