Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1# Copyright (c) 2022-present The Bitcoin Core developers2# Distributed under the MIT software license, see the accompanying3# file COPYING or http://www.opensource.org/licenses/mit-license.php.5"""Test-only implementation of low-level secp256k1 field and group arithmetic7It is designed for ease of understanding, not performance.9WARNING: This code is slow and trivially vulnerable to side channel attacks. Do not use for10anything but tests.12Exports:13* FE: class for secp256k1 field elements14* GE: class for secp256k1 group elements15* G: the secp256k1 generator point16"""18import unittest19from hashlib import sha25620from test_framework.util import assert_equal, assert_not_equal22class FE:23"""Objects of this class represent elements of the field GF(2**256 - 2**32 - 977).25They are represented internally in numerator / denominator form, in order to delay inversions.26"""28# The size of the field (also its modulus and characteristic).29SIZE = 2**256 - 2**32 - 97731def __init__(self, a=0, b=1):32"""Initialize a field element a/b; both a and b can be ints or field elements."""33if isinstance(a, FE):34num = a._num35den = a._den36else:37num = a % FE.SIZE38den = 139if isinstance(b, FE):40den = (den * b._num) % FE.SIZE41num = (num * b._den) % FE.SIZE42else:43den = (den * b) % FE.SIZE44assert_not_equal(den, 0)45if num == 0:46den = 147self._num = num48self._den = den50def __add__(self, a):51"""Compute the sum of two field elements (second may be int)."""52if isinstance(a, FE):53return FE(self._num * a._den + self._den * a._num, self._den * a._den)54return FE(self._num + self._den * a, self._den)56def __radd__(self, a):57"""Compute the sum of an integer and a field element."""58return FE(a) + self60def __sub__(self, a):61"""Compute the difference of two field elements (second may be int)."""62if isinstance(a, FE):63return FE(self._num * a._den - self._den * a._num, self._den * a._den)64return FE(self._num - self._den * a, self._den)66def __rsub__(self, a):67"""Compute the difference of an integer and a field element."""68return FE(a) - self70def __mul__(self, a):71"""Compute the product of two field elements (second may be int)."""72if isinstance(a, FE):73return FE(self._num * a._num, self._den * a._den)74return FE(self._num * a, self._den)76def __rmul__(self, a):77"""Compute the product of an integer with a field element."""78return FE(a) * self80def __truediv__(self, a):81"""Compute the ratio of two field elements (second may be int)."""82return FE(self, a)84def __pow__(self, a):85"""Raise a field element to an integer power."""86return FE(pow(self._num, a, FE.SIZE), pow(self._den, a, FE.SIZE))88def __neg__(self):89"""Negate a field element."""90return FE(-self._num, self._den)92def __int__(self):93"""Convert a field element to an integer in range 0..p-1. The result is cached."""94if self._den != 1:95self._num = (self._num * pow(self._den, -1, FE.SIZE)) % FE.SIZE96self._den = 197return self._num99def sqrt(self):100"""Compute the square root of a field element if it exists (None otherwise).102Due to the fact that our modulus is of the form (p % 4) == 3, the Tonelli-Shanks103algorithm (https://en.wikipedia.org/wiki/Tonelli-Shanks_algorithm) is simply104raising the argument to the power (p + 1) / 4.106To see why: (p-1) % 2 = 0, so 2 divides the order of the multiplicative group,107and thus only half of the non-zero field elements are squares. An element a is108a (nonzero) square when Euler's criterion, a^((p-1)/2) = 1 (mod p), holds. We're109looking for x such that x^2 = a (mod p). Given a^((p-1)/2) = 1, that is equivalent110to x^2 = a^(1 + (p-1)/2) mod p. As (1 + (p-1)/2) is even, this is equivalent to111x = a^((1 + (p-1)/2)/2) mod p, or x = a^((p+1)/4) mod p."""112v = int(self)113s = pow(v, (FE.SIZE + 1) // 4, FE.SIZE)114if s**2 % FE.SIZE == v:115return FE(s)116return None118def is_square(self):119"""Determine if this field element has a square root."""120# A more efficient algorithm is possible here (Jacobi symbol).121return self.sqrt() is not None123def is_even(self):124"""Determine whether this field element, represented as integer in 0..p-1, is even."""125return int(self) & 1 == 0127def __eq__(self, a):128"""Check whether two field elements are equal (second may be an int)."""129if isinstance(a, FE):130return (self._num * a._den - self._den * a._num) % FE.SIZE == 0131return (self._num - self._den * a) % FE.SIZE == 0133def to_bytes(self):134"""Convert a field element to a 32-byte array (BE byte order)."""135return int(self).to_bytes(32, 'big')137@staticmethod138def from_bytes(b):139"""Convert a 32-byte array to a field element (BE byte order, no overflow allowed)."""140v = int.from_bytes(b, 'big')141if v >= FE.SIZE:142return None143return FE(v)145def __str__(self):146"""Convert this field element to a 64 character hex string."""147return f"{int(self):064x}"149def __repr__(self):150"""Get a string representation of this field element."""151return f"FE(0x{int(self):x})"154class GE:155"""Objects of this class represent secp256k1 group elements (curve points or infinity)157Normal points on the curve have fields:158* x: the x coordinate (a field element)159* y: the y coordinate (a field element, satisfying y^2 = x^3 + 7)160* infinity: False162The point at infinity has field:163* infinity: True164"""166# Order of the group (number of points on the curve, plus 1 for infinity)167ORDER = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141169# Number of valid distinct x coordinates on the curve.170ORDER_HALF = ORDER // 2172def __init__(self, x=None, y=None):173"""Initialize a group element with specified x and y coordinates, or infinity."""174if x is None:175# Initialize as infinity.176assert y is None177self.infinity = True178else:179# Initialize as point on the curve (and check that it is).180fx = FE(x)181fy = FE(y)182assert_equal(fy**2, fx**3 + 7)183self.infinity = False184self.x = fx185self.y = fy187def __add__(self, a):188"""Add two group elements together."""189# Deal with infinity: a + infinity == infinity + a == a.190if self.infinity:191return a192if a.infinity:193return self194if self.x == a.x:195if self.y != a.y:196# A point added to its own negation is infinity.197assert_equal(self.y + a.y, 0)198return GE()199else:200# For identical inputs, use the tangent (doubling formula).201lam = (3 * self.x**2) / (2 * self.y)202else:203# For distinct inputs, use the line through both points (adding formula).204lam = (self.y - a.y) / (self.x - a.x)205# Determine point opposite to the intersection of that line with the curve.206x = lam**2 - (self.x + a.x)207y = lam * (self.x - x) - self.y208return GE(x, y)210@staticmethod211def mul(*aps):212"""Compute a (batch) scalar group element multiplication.214GE.mul((a1, p1), (a2, p2), (a3, p3)) is identical to a1*p1 + a2*p2 + a3*p3,215but more efficient."""216# Reduce all the scalars modulo order first (so we can deal with negatives etc).217naps = [(a % GE.ORDER, p) for a, p in aps]218# Start with point at infinity.219r = GE()220# Iterate over all bit positions, from high to low.221for i in range(255, -1, -1):222# Double what we have so far.223r = r + r224# Add then add the points for which the corresponding scalar bit is set.225for (a, p) in naps:226if (a >> i) & 1:227r += p228return r230def __rmul__(self, a):231"""Multiply an integer with a group element."""232if self == G:233return FAST_G.mul(a)234return GE.mul((a, self))236def __neg__(self):237"""Compute the negation of a group element."""238if self.infinity:239return self240return GE(self.x, -self.y)242def to_bytes_compressed(self):243"""Convert a non-infinite group element to 33-byte compressed encoding."""244assert not self.infinity245return bytes([3 - self.y.is_even()]) + self.x.to_bytes()247def to_bytes_uncompressed(self):248"""Convert a non-infinite group element to 65-byte uncompressed encoding."""249assert not self.infinity250return b'\x04' + self.x.to_bytes() + self.y.to_bytes()
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.