module XRBP::Crypto::Key
Constants
- TOKEN_TYPES
Public Class Methods
ed25519(seed=nil)
click to toggle source
@return [Hash] new ed25519 key pair (both public and private components)
# File lib/xrbp/crypto/key.rb, line 63 def self.ed25519(seed=nil) # XXX openssl 1.1.1 needed for EdDSA support: # https://www.openssl.org/blog/blog/2018/09/11/release111/ # Until then use this: require "ed25519" sd, pk = nil if seed sd,pk = seed,seed else sd = Crypto.seed[:seed] pk = Crypto.parse_seed(sd) end sha512 = OpenSSL::Digest::SHA512.new pk = sha512.digest(pk)[0..31] key = Ed25519::SigningKey.new(pk) { :public => key.verify_key.to_bytes.unpack("H*").first.upcase, :private => key.to_bytes.unpack("H*").first.upcase, :seed => sd, :type => :ed25519 } end
secp256k1(seed=nil)
click to toggle source
@return [Hash] new secp256k1 key pair (both public and private components)
# File lib/xrbp/crypto/key.rb, line 20 def self.secp256k1(seed=nil) # XXX: the bitcoin secp256k1 implementation (which rippled pulls in / vendors) # has alot of nuances which require special configuration in openssl. For # the time being, mitigate this by pulling in & using the ruby # btc-secp256k1 bindings: # https://github.com/cryptape/ruby-bitcoin-secp256k1 # # Perhaps at some point, we can look into implementing this logic in pure-ruby: # https://medium.com/coinmonks/introduction-to-blockchains-bedrock-the-elliptic-curve-secp256k1-e4bd3bc17d require 'secp256k1' spk = Secp256k1::PrivateKey.new sd, pk = nil if seed sd,pk = seed,seed else sd = Crypto.seed[:seed] pk = Crypto.parse_seed(sd) end # FIXME: rippled & ripple-keypairs (& by extension ripple-lib) repeatedly # hash seed until certain it is less than the order of the # curve, we should do this as well (for security) # # https://github.com/ripple/rippled/blob/develop/src/ripple/crypto/impl/GenerateDeterministicKey.cpp # https://github.com/ripple/ripple-keypairs/blob/master/src/secp256k1.js # # Also look into if setting raw key here has same effect as # secp256k1.mul (as invoked in keypairs) sha512 = OpenSSL::Digest::SHA512.new pk = sha512.digest(pk)[0..31] spk.set_raw_privkey pk { :public => spk.pubkey.serialize.unpack("H*").first, :private => spk.send(:serialize), :seed => sd, :type => :secp256k1 } end
sign_digest(key, data)
click to toggle source
Sign the digest using the specified key, returning the result
@param key [Hash] key to sign digest with @param data [String] data to sign (must be exactly 32 bytes long!) @return [String] signed digest
# File lib/xrbp/crypto/key.rb, line 95 def self.sign_digest(key, data) raise "unknown key" unless key.is_a?(Hash) && key[:type] && key[:private] raise "invalid data" unless data.length == 32 if key[:type] == :secp256k1 require 'secp256k1' pk = Secp256k1::PrivateKey.new pk.set_raw_privkey [key[:private]].pack("H*") sig_raw = pk.ecdsa_sign data, raw: true return pk.ecdsa_serialize sig_raw elsif key[:type] == :ed25519 require "ed25519" sd = key[:seed] pk = Crypto.parse_seed(sd) sha512 = OpenSSL::Digest::SHA512.new pk = sha512.digest(pk)[0..31] pk = Ed25519::SigningKey.new(pk) return pk.sign(data) end raise "unknown key type" end
verify(key, data, expected)
click to toggle source
Returns bool indicating if data is the result of signing expected value with given key.
@param key [Hash] key to use to verify digest @param data [String] signed data @param expected [String] original unsigned data @return [Bool] indicating if signed digest matches
original data
# File lib/xrbp/crypto/key.rb, line 131 def self.verify(key, data, expected) if key[:type] == :secp256k1 require 'secp256k1' pb = Secp256k1::PublicKey.new :pubkey => [key[:public]].pack("H*"), :raw => true pv = Secp256k1::PrivateKey.new return pb.ecdsa_verify expected, pv.ecdsa_deserialize(data), raw: true elsif key[:type] == :ed25519 require "ed25519" pk = Ed25519::VerifyKey.new([key[:public]].pack("H*")) begin return pk.verify(data, expected) rescue Ed25519::VerifyError return false end end raise "unknown key type" end