Module: Rb25519

Defined in:
lib/rb-pure25519.rb

Defined Under Namespace

Classes: FField

Constant Summary collapse

CURVE =

Module Methods

FField::EC25519.new
BASE_XZ =
[ CURVE.field[9], CURVE.field[1] ]

Class Method Summary collapse

Class Method Details

.clamp_string(str) ⇒ Object



731
732
733
734
735
736
737
738
# File 'lib/rb-pure25519.rb', line 731

def self.clamp_string(str)
  bytes = str.each_byte.to_a
  bytes[0] &= 248;
  bytes[31] &= 127;
  bytes[31] |= 64;

  return bytes.pack('c*')
end

.number_to_string(v) ⇒ Object



722
723
724
725
726
727
728
729
# File 'lib/rb-pure25519.rb', line 722

def self.number_to_string(v)
  ary = []
  while v > 0
    ary << (v & 0xFF)
    v >>= 8
  end
  ary.pack('c*')
end

.public_key_num(secret) ⇒ Object



753
754
755
756
757
758
759
760
# File 'lib/rb-pure25519.rb', line 753

def self.public_key_num(secret)
  if String === secret
    secret = string_to_number(secret)
  end

  xz = CURVE.scale_proj( secret, BASE_XZ )
  (xz[0] / xz[1]).to_i
end

.public_key_str(secret) ⇒ Object



763
764
765
# File 'lib/rb-pure25519.rb', line 763

def self.public_key_str(secret)
  number_to_string( public_key_num(secret) )
end

.random_secret_numObject



746
747
748
# File 'lib/rb-pure25519.rb', line 746

def self.random_secret_num
  string_to_number(random_secret_str)
end

.random_secret_strObject



740
741
742
743
744
# File 'lib/rb-pure25519.rb', line 740

def self.random_secret_str
  rv = SecureRandom.random_bytes(32)
  rv = clamp_string(rv)
  rv
end

.shared_secret_num(pkey, skey) ⇒ Object

Secret is a ‘k’ in Q = k*P

We want to calculate:

P_shared_secret = (skey + other_skey) * P_base

We get there because:

P_other_pkey = (other_skey) * P_base

So continuing to scale P_other_pkey by ‘skey` will get us to P_shared_secret. The other party is also doing this calculation; the Abelian group property means this operation is commutative.

Note that the Points are all X points in XZ projective space.



786
787
788
789
790
791
792
793
794
795
796
797
# File 'lib/rb-pure25519.rb', line 786

def self.shared_secret_num(pkey, skey)
  if String === pkey
    pkey = string_to_number(pkey)
  end
  if String === skey
    skey = string_to_number(skey)
  end

  shared_xz = CURVE.scale_proj( skey, [ CURVE.field[pkey], CURVE.field[1] ] )

  (shared_xz[0] / shared_xz[1]).to_i    # Final projective -> affine inversion
end

.shared_secret_str(pkey, skey) ⇒ Object



799
800
801
# File 'lib/rb-pure25519.rb', line 799

def self.shared_secret_str(pkey, skey)
  number_to_string( shared_secret_num(pkey, skey) )
end

.string_to_number(val) ⇒ Object



714
715
716
717
718
719
720
# File 'lib/rb-pure25519.rb', line 714

def self.string_to_number(val)
  v = 0
  val.reverse.each_byte do |byte| 
    v = (v << 8) | byte
  end
  v
end