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""" Generates the constants used in secp256k1_scalar_split_lambda.3See the comments for secp256k1_scalar_split_lambda in src/scalar_impl.h for detailed explanations.4"""6load("secp256k1_params.sage")8def inf_norm(v):9"""Returns the infinity norm of a vector."""10return max(map(abs, v))12def gauss_reduction(i1, i2):13v1, v2 = i1.copy(), i2.copy()14while True:15if inf_norm(v2) < inf_norm(v1):16v1, v2 = v2, v117# This is essentially18# m = round((v1[0]*v2[0] + v1[1]*v2[1]) / (inf_norm(v1)**2))19# (rounding to the nearest integer) without relying on floating point arithmetic.20m = ((v1[0]*v2[0] + v1[1]*v2[1]) + (inf_norm(v1)**2) // 2) // (inf_norm(v1)**2)21if m == 0:22return v1, v223v2[0] -= m*v1[0]24v2[1] -= m*v1[1]26def find_split_constants_gauss():27"""Find constants for secp256k1_scalar_split_lamdba using gauss reduction."""28(v11, v12), (v21, v22) = gauss_reduction([0, N], [1, int(LAMBDA)])30# We use related vectors in secp256k1_scalar_split_lambda.31A1, B1 = -v21, -v1132A2, B2 = v22, -v2134return A1, B1, A2, B236def find_split_constants_explicit_tof():37"""Find constants for secp256k1_scalar_split_lamdba using the trace of Frobenius.39See Benjamin Smith: "Easy scalar decompositions for efficient scalar multiplication on40elliptic curves and genus 2 Jacobians" (https://eprint.iacr.org/2013/672), Example 241"""42assert P % 3 == 1 # The paper says P % 3 == 2 but that appears to be a mistake, see [10].43assert C.j_invariant() == 045t = C.trace_of_frobenius()47c = Integer(sqrt((4*P - t**2)/3))48A1 = Integer((t - c)/2 - 1)49B1 = c51A2 = Integer((t + c)/2 - 1)52B2 = Integer(1 - (t - c)/2)54# We use a negated b values in secp256k1_scalar_split_lambda.55B1, B2 = -B1, -B257return A1, B1, A2, B259A1, B1, A2, B2 = find_split_constants_explicit_tof()61# For extra fun, use an independent method to recompute the constants.62assert (A1, B1, A2, B2) == find_split_constants_gauss()64# PHI : Z[l] -> Z_n where phi(a + b*l) == a + b*lambda mod n.65def PHI(a,b):66return Z(a + LAMBDA*b)68# Check that (A1, B1) and (A2, B2) are in the kernel of PHI.69assert PHI(A1, B1) == Z(0)70assert PHI(A2, B2) == Z(0)72# Check that the parallelogram generated by (A1, A2) and (B1, B2)73# is a fundamental domain by containing exactly N points.74# Since the LHS is the determinant and N != 0, this also checks that75# (A1, A2) and (B1, B2) are linearly independent. By the previous76# assertions, (A1, A2) and (B1, B2) are a basis of the kernel.77assert A1*B2 - B1*A2 == N79# Check that their components are short enough.80assert (A1 + A2)/2 < sqrt(N)81assert B1 < sqrt(N)82assert B2 < sqrt(N)84# Verify connection to Eisenstein integers Z[w] where w = (-1 + sqrt(-3))/2.85# The group order N factors as N = pi * conj(pi) in Z[w], where pi = A - B*w86# is an Eisenstein prime with norm A^2 + A*B + B^2. The GLV endomorphism87# eigenvalue LAMBDA equals B/A mod N, which is the image of w^2 under the88# isomorphism Z[w]/(pi) -> Z/NZ (since w -> A/B and (A/B)^2 = B/A in Z/NZ).89A_EIS, B_EIS = -B1, A190assert A_EIS**2 + A_EIS*B_EIS + B_EIS**2 == N91assert Z(B_EIS / A_EIS) == LAMBDA93G1 = round((2**384)*B2/N)94G2 = round((2**384)*(-B1)/N)96def rnddiv2(v):97if v & 1:98v += 199return v >> 1101def scalar_lambda_split(k):102"""Equivalent to secp256k1_scalar_lambda_split()."""103c1 = rnddiv2((k * G1) >> 383)104c2 = rnddiv2((k * G2) >> 383)105c1 = (c1 * -B1) % N106c2 = (c2 * -B2) % N107r2 = (c1 + c2) % N108r1 = (k + r2 * -LAMBDA) % N109return (r1, r2)111# The result of scalar_lambda_split can depend on the representation of k (mod n).112SPECIAL = (2**383) // G2 + 1113assert scalar_lambda_split(SPECIAL) != scalar_lambda_split(SPECIAL + N)115print(' A1 =', hex(A1))116print(' -B1 =', hex(-B1))117print(' A2 =', hex(A2))118print(' -B2 =', hex(-B2))119print(' =', hex(Z(-B2)))120print(' -LAMBDA =', hex(-LAMBDA))122print(' G1 =', hex(G1))123print(' G2 =', hex(G2))
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.