Module Secp256k1
Pure Ruby secp256k1 elliptic curve implementation.
Provides field arithmetic, point operations with Jacobian coordinates, and windowed-NAF scalar multiplication. Ported from the BSV TypeScript SDK reference implementation.
All field operations work on plain Ruby Integer values (arbitrary precision,
C-backed in MRI). No external gems required.
Constants
GX
Generator point x-coordinate.
GY
Generator point y-coordinate.
HALF_N
Half the curve order, used for low-S normalisation (BIP-62).
JP_INFINITY
Not documented.
MASK_256
256-bit mask for fast reduction.
N
The curve order (number of points on the curve).
P
The secp256k1 field prime: p = 2^256 - 2^32 - 977
P_PLUS1_DIV4
(P + 1) / 4 — used for modular square root since P ≡ 3 (mod 4).
VERSION
Not documented.
WNAF_CACHE_MAX
Maximum number of entries kept in the wNAF precomputation cache. Bounds memory usage for long-running processes (e.g. servers).
WNAF_TABLE_CACHE
Cache for precomputed wNAF tables, keyed by “window:x:y”. FIFO eviction: the oldest inserted entry is dropped when the cap is reached (Hash preserves insertion order; we delete the first key). Bounded at WNAF_CACHE_MAX entries; keyed only on the public base point — no secret-scalar exposure.
Public Class Methods
allow_pure_ruby_ct!()
Explicitly allow constant-time operations in pure-Ruby mode. Call this only after evaluating the risks documented in docs/risks.md.
bytes_to_int(bytes)
Convert a big-endian binary string to an Integer.
- @param
bytes[String] binary string (ASCII-8BIT) - @return [Integer]
fadd(a, b)
Modular addition in the field.
finv(a)
Modular multiplicative inverse in the field (Fermat’s little theorem).
- @param
a[Integer] value to invert (must be non-zero mod P) - @raise [ArgumentError] if a is zero mod P
- @return [Integer] a^(P-2) mod P
fmul(a, b)
Modular multiplication in the field.
fneg(a)
Modular negation in the field.
Canonicalises the operand so the result matches the C wrapper for any non-negative 256-bit input — see {#fsub} for the negative-input note.
fred(x)
Fast reduction modulo the secp256k1 prime.
Exploits the structure P = 2^256 - 2^32 - 977 to avoid generic modular division. Two folding passes plus a conditional subtraction.
- @param
x[Integer] non-negative integer - @return [Integer] x mod P, in range [0, P)
fsqr(a)
Modular squaring in the field.
fsqrt(a)
Modular square root in the field.
Uses the identity sqrt(a) = a^((P+1)/4) mod P, valid because P ≡ 3 (mod 4).
Returns nil if a is not a quadratic residue.
- @param
a[Integer] - @return [Integer, nil] the square root, or nil if none exists
fsub(a, b)
Modular subtraction in the field.
Canonicalises both operands so the result matches the C wrapper for any non-negative 256-bit input — load-bearing for the dfuzz differential, where pure-Ruby serves as the oracle. The dfuzz harness only feeds non-negative inputs (xorshift output, plus structured P-band vectors), so the differential never observes the negative case.
Note: pure-Ruby accepts negative inputs (Ruby % canonicalises them); the C
wrapper rejects negatives via rb_to_uint256. Backend parity holds for all >=
0 inputs; intentional divergence on negatives.
int_to_bytes(n, length = 32)
Convert an Integer to a fixed-length big-endian binary string.
- @param
n[Integer] the integer to convert - @param
length[Integer] desired byte length (default 32) - @raise [ArgumentError]
- @return [String] binary string (ASCII-8BIT)
jp_add(p, q)
Add two Jacobian points.
- @param
p[Array] first Jacobian point - @param
q[Array] second Jacobian point - @return [Array] resulting Jacobian point
jp_double(p)
Double a Jacobian point.
Formula from hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html (a=0 for secp256k1).
- @param
p[Array(Integer, Integer, Integer)] Jacobian point [X, Y, Z] - @return [Array(Integer, Integer, Integer)]
jp_neg(p)
Negate a Jacobian point.
jp_to_affine(jp)
Convert a Jacobian point to affine coordinates.
- @param
jp[Array(Integer, Integer, Integer)] - @return [Array(Integer, Integer)] affine [x, y], or nil for infinity
native?()
Whether the native C extension is loaded and active.
- @return [Boolean]
pure_ruby_ct_allowed?()
- @api private
- @return [Boolean]
scalar_add(a, b)
Scalar addition mod N.
scalar_inv(a)
Scalar multiplicative inverse (Fermat).
- @raise [ArgumentError] if a is zero mod N
scalar_mod(a)
Reduce modulo the curve order.
scalar_mul(a, b)
Scalar multiplication mod N.