Added detailed pseudocode for elliptic curve algorithms covering modular arithmetic, point operations, scalar multiplication, and coordinate conversions. Also introduced a comprehensive knowledge base for distributed systems, including CAP theorem, consistency models, consensus protocols (e.g., Paxos, Raft, PBFT, Nakamoto), and fault-tolerant design principles.
513 lines
11 KiB
Markdown
513 lines
11 KiB
Markdown
# Elliptic Curve Algorithms
|
|
|
|
Detailed pseudocode for core elliptic curve operations.
|
|
|
|
## Field Arithmetic
|
|
|
|
### Modular Addition
|
|
|
|
```
|
|
function mod_add(a, b, p):
|
|
result = a + b
|
|
if result >= p:
|
|
result = result - p
|
|
return result
|
|
```
|
|
|
|
### Modular Subtraction
|
|
|
|
```
|
|
function mod_sub(a, b, p):
|
|
if a >= b:
|
|
return a - b
|
|
else:
|
|
return p - b + a
|
|
```
|
|
|
|
### Modular Multiplication
|
|
|
|
For general case:
|
|
```
|
|
function mod_mul(a, b, p):
|
|
return (a * b) mod p
|
|
```
|
|
|
|
For secp256k1 optimized (Barrett reduction):
|
|
```
|
|
function mod_mul_secp256k1(a, b):
|
|
# Compute full 512-bit product
|
|
product = a * b
|
|
|
|
# Split into high and low 256-bit parts
|
|
low = product & ((1 << 256) - 1)
|
|
high = product >> 256
|
|
|
|
# Reduce: result ≡ low + high * (2³² + 977) (mod p)
|
|
result = low + high * (1 << 32) + high * 977
|
|
|
|
# May need additional reduction
|
|
while result >= p:
|
|
result = result - p
|
|
|
|
return result
|
|
```
|
|
|
|
### Modular Inverse
|
|
|
|
**Extended Euclidean Algorithm**:
|
|
```
|
|
function mod_inverse(a, p):
|
|
if a == 0:
|
|
error "No inverse exists for 0"
|
|
|
|
old_r, r = p, a
|
|
old_s, s = 0, 1
|
|
|
|
while r != 0:
|
|
quotient = old_r / r
|
|
old_r, r = r, old_r - quotient * r
|
|
old_s, s = s, old_s - quotient * s
|
|
|
|
if old_r != 1:
|
|
error "No inverse exists"
|
|
|
|
if old_s < 0:
|
|
old_s = old_s + p
|
|
|
|
return old_s
|
|
```
|
|
|
|
**Fermat's Little Theorem** (for prime p):
|
|
```
|
|
function mod_inverse_fermat(a, p):
|
|
return mod_exp(a, p - 2, p)
|
|
```
|
|
|
|
### Modular Exponentiation (Square-and-Multiply)
|
|
|
|
```
|
|
function mod_exp(base, exp, p):
|
|
result = 1
|
|
base = base mod p
|
|
|
|
while exp > 0:
|
|
if exp & 1: # exp is odd
|
|
result = (result * base) mod p
|
|
exp = exp >> 1
|
|
base = (base * base) mod p
|
|
|
|
return result
|
|
```
|
|
|
|
### Modular Square Root (Tonelli-Shanks)
|
|
|
|
For secp256k1 where p ≡ 3 (mod 4):
|
|
```
|
|
function mod_sqrt(a, p):
|
|
# For p ≡ 3 (mod 4), sqrt(a) = a^((p+1)/4)
|
|
return mod_exp(a, (p + 1) / 4, p)
|
|
```
|
|
|
|
## Point Operations
|
|
|
|
### Point Validation
|
|
|
|
```
|
|
function is_on_curve(P, a, b, p):
|
|
if P is infinity:
|
|
return true
|
|
|
|
x, y = P
|
|
left = (y * y) mod p
|
|
right = (x * x * x + a * x + b) mod p
|
|
|
|
return left == right
|
|
```
|
|
|
|
### Point Addition (Affine Coordinates)
|
|
|
|
```
|
|
function point_add(P, Q, a, p):
|
|
if P is infinity:
|
|
return Q
|
|
if Q is infinity:
|
|
return P
|
|
|
|
x1, y1 = P
|
|
x2, y2 = Q
|
|
|
|
if x1 == x2:
|
|
if y1 == mod_neg(y2, p): # P = -Q
|
|
return infinity
|
|
else: # P == Q
|
|
return point_double(P, a, p)
|
|
|
|
# λ = (y2 - y1) / (x2 - x1)
|
|
numerator = mod_sub(y2, y1, p)
|
|
denominator = mod_sub(x2, x1, p)
|
|
λ = mod_mul(numerator, mod_inverse(denominator, p), p)
|
|
|
|
# x3 = λ² - x1 - x2
|
|
x3 = mod_sub(mod_sub(mod_mul(λ, λ, p), x1, p), x2, p)
|
|
|
|
# y3 = λ(x1 - x3) - y1
|
|
y3 = mod_sub(mod_mul(λ, mod_sub(x1, x3, p), p), y1, p)
|
|
|
|
return (x3, y3)
|
|
```
|
|
|
|
### Point Doubling (Affine Coordinates)
|
|
|
|
```
|
|
function point_double(P, a, p):
|
|
if P is infinity:
|
|
return infinity
|
|
|
|
x, y = P
|
|
|
|
if y == 0:
|
|
return infinity
|
|
|
|
# λ = (3x² + a) / (2y)
|
|
numerator = mod_add(mod_mul(3, mod_mul(x, x, p), p), a, p)
|
|
denominator = mod_mul(2, y, p)
|
|
λ = mod_mul(numerator, mod_inverse(denominator, p), p)
|
|
|
|
# x3 = λ² - 2x
|
|
x3 = mod_sub(mod_mul(λ, λ, p), mod_mul(2, x, p), p)
|
|
|
|
# y3 = λ(x - x3) - y
|
|
y3 = mod_sub(mod_mul(λ, mod_sub(x, x3, p), p), y, p)
|
|
|
|
return (x3, y3)
|
|
```
|
|
|
|
### Point Negation
|
|
|
|
```
|
|
function point_negate(P, p):
|
|
if P is infinity:
|
|
return infinity
|
|
|
|
x, y = P
|
|
return (x, p - y)
|
|
```
|
|
|
|
## Scalar Multiplication
|
|
|
|
### Double-and-Add (Left-to-Right)
|
|
|
|
```
|
|
function scalar_mult_double_add(k, P, a, p):
|
|
if k == 0 or P is infinity:
|
|
return infinity
|
|
|
|
if k < 0:
|
|
k = -k
|
|
P = point_negate(P, p)
|
|
|
|
R = infinity
|
|
bits = binary_representation(k) # MSB first
|
|
|
|
for bit in bits:
|
|
R = point_double(R, a, p)
|
|
if bit == 1:
|
|
R = point_add(R, P, a, p)
|
|
|
|
return R
|
|
```
|
|
|
|
### Montgomery Ladder (Constant-Time)
|
|
|
|
```
|
|
function scalar_mult_montgomery(k, P, a, p):
|
|
R0 = infinity
|
|
R1 = P
|
|
|
|
bits = binary_representation(k) # MSB first
|
|
|
|
for bit in bits:
|
|
if bit == 0:
|
|
R1 = point_add(R0, R1, a, p)
|
|
R0 = point_double(R0, a, p)
|
|
else:
|
|
R0 = point_add(R0, R1, a, p)
|
|
R1 = point_double(R1, a, p)
|
|
|
|
return R0
|
|
```
|
|
|
|
### w-NAF Scalar Multiplication
|
|
|
|
```
|
|
function compute_wNAF(k, w):
|
|
# Convert scalar to width-w Non-Adjacent Form
|
|
naf = []
|
|
|
|
while k > 0:
|
|
if k & 1: # k is odd
|
|
# Get w-bit window
|
|
digit = k mod (1 << w)
|
|
if digit >= (1 << (w-1)):
|
|
digit = digit - (1 << w)
|
|
naf.append(digit)
|
|
k = k - digit
|
|
else:
|
|
naf.append(0)
|
|
k = k >> 1
|
|
|
|
return naf
|
|
|
|
function scalar_mult_wNAF(k, P, w, a, p):
|
|
# Precompute odd multiples: [P, 3P, 5P, ..., (2^(w-1)-1)P]
|
|
precomp = [P]
|
|
P2 = point_double(P, a, p)
|
|
for i in range(1, 1 << (w-1)):
|
|
precomp.append(point_add(precomp[-1], P2, a, p))
|
|
|
|
# Convert k to w-NAF
|
|
naf = compute_wNAF(k, w)
|
|
|
|
# Compute scalar multiplication
|
|
R = infinity
|
|
for i in range(len(naf) - 1, -1, -1):
|
|
R = point_double(R, a, p)
|
|
digit = naf[i]
|
|
if digit > 0:
|
|
R = point_add(R, precomp[(digit - 1) / 2], a, p)
|
|
elif digit < 0:
|
|
R = point_add(R, point_negate(precomp[(-digit - 1) / 2], p), a, p)
|
|
|
|
return R
|
|
```
|
|
|
|
### Shamir's Trick (Multi-Scalar)
|
|
|
|
For computing k₁P + k₂Q efficiently:
|
|
|
|
```
|
|
function multi_scalar_mult(k1, P, k2, Q, a, p):
|
|
# Precompute P + Q
|
|
PQ = point_add(P, Q, a, p)
|
|
|
|
# Get binary representations (same length, padded)
|
|
bits1 = binary_representation(k1)
|
|
bits2 = binary_representation(k2)
|
|
max_len = max(len(bits1), len(bits2))
|
|
bits1 = pad_left(bits1, max_len)
|
|
bits2 = pad_left(bits2, max_len)
|
|
|
|
R = infinity
|
|
|
|
for i in range(max_len):
|
|
R = point_double(R, a, p)
|
|
|
|
b1, b2 = bits1[i], bits2[i]
|
|
|
|
if b1 == 1 and b2 == 1:
|
|
R = point_add(R, PQ, a, p)
|
|
elif b1 == 1:
|
|
R = point_add(R, P, a, p)
|
|
elif b2 == 1:
|
|
R = point_add(R, Q, a, p)
|
|
|
|
return R
|
|
```
|
|
|
|
## Jacobian Coordinates
|
|
|
|
More efficient for repeated operations.
|
|
|
|
### Conversion
|
|
|
|
```
|
|
# Affine to Jacobian
|
|
function affine_to_jacobian(P):
|
|
if P is infinity:
|
|
return (1, 1, 0) # Jacobian infinity
|
|
x, y = P
|
|
return (x, y, 1)
|
|
|
|
# Jacobian to Affine
|
|
function jacobian_to_affine(P, p):
|
|
X, Y, Z = P
|
|
if Z == 0:
|
|
return infinity
|
|
|
|
Z_inv = mod_inverse(Z, p)
|
|
Z_inv2 = mod_mul(Z_inv, Z_inv, p)
|
|
Z_inv3 = mod_mul(Z_inv2, Z_inv, p)
|
|
|
|
x = mod_mul(X, Z_inv2, p)
|
|
y = mod_mul(Y, Z_inv3, p)
|
|
|
|
return (x, y)
|
|
```
|
|
|
|
### Point Doubling (Jacobian)
|
|
|
|
For curve y² = x³ + 7 (a = 0):
|
|
|
|
```
|
|
function jacobian_double(P, p):
|
|
X, Y, Z = P
|
|
|
|
if Y == 0:
|
|
return (1, 1, 0) # infinity
|
|
|
|
# For a = 0: M = 3*X²
|
|
S = mod_mul(4, mod_mul(X, mod_mul(Y, Y, p), p), p)
|
|
M = mod_mul(3, mod_mul(X, X, p), p)
|
|
|
|
X3 = mod_sub(mod_mul(M, M, p), mod_mul(2, S, p), p)
|
|
Y3 = mod_sub(mod_mul(M, mod_sub(S, X3, p), p),
|
|
mod_mul(8, mod_mul(Y, Y, mod_mul(Y, Y, p), p), p), p)
|
|
Z3 = mod_mul(2, mod_mul(Y, Z, p), p)
|
|
|
|
return (X3, Y3, Z3)
|
|
```
|
|
|
|
### Point Addition (Jacobian + Affine)
|
|
|
|
Mixed addition is faster when one point is in affine:
|
|
|
|
```
|
|
function jacobian_add_affine(P, Q, p):
|
|
# P in Jacobian (X1, Y1, Z1), Q in affine (x2, y2)
|
|
X1, Y1, Z1 = P
|
|
x2, y2 = Q
|
|
|
|
if Z1 == 0:
|
|
return affine_to_jacobian(Q)
|
|
|
|
Z1Z1 = mod_mul(Z1, Z1, p)
|
|
U2 = mod_mul(x2, Z1Z1, p)
|
|
S2 = mod_mul(y2, mod_mul(Z1, Z1Z1, p), p)
|
|
|
|
H = mod_sub(U2, X1, p)
|
|
HH = mod_mul(H, H, p)
|
|
I = mod_mul(4, HH, p)
|
|
J = mod_mul(H, I, p)
|
|
r = mod_mul(2, mod_sub(S2, Y1, p), p)
|
|
V = mod_mul(X1, I, p)
|
|
|
|
X3 = mod_sub(mod_sub(mod_mul(r, r, p), J, p), mod_mul(2, V, p), p)
|
|
Y3 = mod_sub(mod_mul(r, mod_sub(V, X3, p), p), mod_mul(2, mod_mul(Y1, J, p), p), p)
|
|
Z3 = mod_mul(mod_sub(mod_mul(mod_add(Z1, H, p), mod_add(Z1, H, p), p),
|
|
mod_add(Z1Z1, HH, p), p), 1, p)
|
|
|
|
return (X3, Y3, Z3)
|
|
```
|
|
|
|
## GLV Endomorphism (secp256k1)
|
|
|
|
### Scalar Decomposition
|
|
|
|
```
|
|
# Constants for secp256k1
|
|
LAMBDA = 0x5363AD4CC05C30E0A5261C028812645A122E22EA20816678DF02967C1B23BD72
|
|
BETA = 0x7AE96A2B657C07106E64479EAC3434E99CF0497512F58995C1396C28719501EE
|
|
|
|
# Decomposition coefficients
|
|
A1 = 0x3086D221A7D46BCDE86C90E49284EB15
|
|
B1 = 0x114CA50F7A8E2F3F657C1108D9D44CFD8
|
|
A2 = 0xE4437ED6010E88286F547FA90ABFE4C3
|
|
B2 = A1
|
|
|
|
function glv_decompose(k, n):
|
|
# Compute c1 = round(b2 * k / n)
|
|
# Compute c2 = round(-b1 * k / n)
|
|
c1 = (B2 * k + n // 2) // n
|
|
c2 = (-B1 * k + n // 2) // n
|
|
|
|
# k1 = k - c1*A1 - c2*A2
|
|
# k2 = -c1*B1 - c2*B2
|
|
k1 = k - c1 * A1 - c2 * A2
|
|
k2 = -c1 * B1 - c2 * B2
|
|
|
|
return (k1, k2)
|
|
|
|
function glv_scalar_mult(k, P, p, n):
|
|
k1, k2 = glv_decompose(k, n)
|
|
|
|
# Compute endomorphism: φ(P) = (β*x, y)
|
|
x, y = P
|
|
phi_P = (mod_mul(BETA, x, p), y)
|
|
|
|
# Use Shamir's trick: k1*P + k2*φ(P)
|
|
return multi_scalar_mult(k1, P, k2, phi_P, 0, p)
|
|
```
|
|
|
|
## Batch Inversion
|
|
|
|
Amortize expensive inversions over multiple points:
|
|
|
|
```
|
|
function batch_invert(values, p):
|
|
n = len(values)
|
|
if n == 0:
|
|
return []
|
|
|
|
# Compute cumulative products
|
|
products = [values[0]]
|
|
for i in range(1, n):
|
|
products.append(mod_mul(products[-1], values[i], p))
|
|
|
|
# Invert the final product
|
|
inv = mod_inverse(products[-1], p)
|
|
|
|
# Compute individual inverses
|
|
inverses = [0] * n
|
|
for i in range(n - 1, 0, -1):
|
|
inverses[i] = mod_mul(inv, products[i - 1], p)
|
|
inv = mod_mul(inv, values[i], p)
|
|
inverses[0] = inv
|
|
|
|
return inverses
|
|
```
|
|
|
|
## Key Generation
|
|
|
|
```
|
|
function generate_keypair(G, n, p):
|
|
# Generate random private key
|
|
d = random_integer(1, n - 1)
|
|
|
|
# Compute public key
|
|
Q = scalar_mult(d, G)
|
|
|
|
return (d, Q)
|
|
```
|
|
|
|
## Point Compression/Decompression
|
|
|
|
```
|
|
function compress_point(P, p):
|
|
if P is infinity:
|
|
return bytes([0x00])
|
|
|
|
x, y = P
|
|
prefix = 0x02 if (y % 2 == 0) else 0x03
|
|
return bytes([prefix]) + x.to_bytes(32, 'big')
|
|
|
|
function decompress_point(compressed, a, b, p):
|
|
prefix = compressed[0]
|
|
|
|
if prefix == 0x00:
|
|
return infinity
|
|
|
|
x = int.from_bytes(compressed[1:], 'big')
|
|
|
|
# Compute y² = x³ + ax + b
|
|
y_squared = mod_add(mod_add(mod_mul(x, mod_mul(x, x, p), p),
|
|
mod_mul(a, x, p), p), b, p)
|
|
|
|
# Compute y = sqrt(y²)
|
|
y = mod_sqrt(y_squared, p)
|
|
|
|
# Select correct y based on prefix
|
|
if (prefix == 0x02) != (y % 2 == 0):
|
|
y = p - y
|
|
|
|
return (x, y)
|
|
``` |