From 22b8ddd6dff667831684b64abb72b906f8e1ba12 Mon Sep 17 00:00:00 2001 From: "gh.cien" Date: Fri, 5 Dec 2025 17:00:35 +0100 Subject: [PATCH 1/2] Refactor ED25519 curve checker for improved y-coordinate extraction and modular arithmetic; update token account hash function for strict binary encoding. --- lib/solana_ruby/ed25519_curve_checker.rb | 19 +++++++++++++++---- .../transaction_helpers/token_account.rb | 3 ++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/lib/solana_ruby/ed25519_curve_checker.rb b/lib/solana_ruby/ed25519_curve_checker.rb index 328cfe2..6b3a542 100644 --- a/lib/solana_ruby/ed25519_curve_checker.rb +++ b/lib/solana_ruby/ed25519_curve_checker.rb @@ -10,12 +10,23 @@ class Ed25519CurveChecker def self.on_curve?(public_key) return false unless public_key.bytesize == 32 # Must be exactly 32 bytes - # Extract y-coordinate from the public key - y = public_key.unpack1("H*").to_i(16) % Q + # Extract bytes - needed for bitwise operations + y_bytes = public_key.bytes + # Ed25519 Curve does not use the x sign bit, y value is (0-254) so we need to clear the bit 255 (x sign bit) + # Byte 31, bit 7 is the sign bit + y_bytes[31] &= 0x7F # binary 01111111 + + # shift left bytes by 8 bits to get little-endian order then sum to get integer + # In little-endian: byte[0] is 2^0, byte[1] is 2^8, ..., byte[31] is 2^248 + y = y_bytes.each_with_index.sum { |byte, index| byte << (8 * index) } + + # Reduce modulo Q (field arithmetic) to ensure it's within the valid range + y = y % Q # Compute x² from the Ed25519 curve equation: x² = (y² - 1) / (d * y² + 1) mod Q - numerator = (y**2 - 1) % Q - denominator = (D * y**2 + 1) % Q + y_squared = y**2 + numerator = (y_squared - 1) % Q + denominator = (D * y_squared + 1) % Q # Compute the modular inverse of the denominator denominator_inv = OpenSSL::BN.new(denominator).mod_inverse(Q).to_i rescue nil diff --git a/lib/solana_ruby/transaction_helpers/token_account.rb b/lib/solana_ruby/transaction_helpers/token_account.rb index d6a3d6d..02d96a9 100644 --- a/lib/solana_ruby/transaction_helpers/token_account.rb +++ b/lib/solana_ruby/transaction_helpers/token_account.rb @@ -65,7 +65,8 @@ def self.find_program_address(seeds, program_id) def self.hash_seeds(seeds, program_id) # Combine seeds and program ID with the PDA derivation logic - buffer = seeds.flatten.join + program_id + "ProgramDerivedAddress" + # strict encoding to binary + buffer = seeds.join.b + program_id.b + "ProgramDerivedAddress".b RbNaCl::Hash.sha256(buffer) end end From ab7de8ca0c57130cbb5dbe721129ab2300009fb0 Mon Sep 17 00:00:00 2001 From: "gh.cien" Date: Mon, 22 Dec 2025 15:38:23 +0100 Subject: [PATCH 2/2] Optimize modular arithmetic in ED25519 curve checker by refining y-coordinate calculations and ensuring correct field operations. --- lib/solana_ruby/ed25519_curve_checker.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/solana_ruby/ed25519_curve_checker.rb b/lib/solana_ruby/ed25519_curve_checker.rb index 6b3a542..37834cc 100644 --- a/lib/solana_ruby/ed25519_curve_checker.rb +++ b/lib/solana_ruby/ed25519_curve_checker.rb @@ -21,10 +21,9 @@ def self.on_curve?(public_key) y = y_bytes.each_with_index.sum { |byte, index| byte << (8 * index) } # Reduce modulo Q (field arithmetic) to ensure it's within the valid range - y = y % Q - + y = y % Q # Compute x² from the Ed25519 curve equation: x² = (y² - 1) / (d * y² + 1) mod Q - y_squared = y**2 + y_squared = (y * y) % Q numerator = (y_squared - 1) % Q denominator = (D * y_squared + 1) % Q