483 lines
12 KiB
Go
483 lines
12 KiB
Go
package p256k1
|
|
|
|
import (
|
|
"errors"
|
|
"unsafe"
|
|
)
|
|
|
|
// Precomputed table configuration
|
|
const (
|
|
// Window size for precomputed tables (4 bits = 16 entries per window)
|
|
EcmultWindowSize = 4
|
|
EcmultTableSize = 1 << EcmultWindowSize // 16
|
|
|
|
// Number of windows needed for 256-bit scalars
|
|
EcmultWindows = (256 + EcmultWindowSize - 1) / EcmultWindowSize // 64 windows
|
|
|
|
// Generator multiplication table configuration
|
|
EcmultGenWindowSize = 4
|
|
EcmultGenTableSize = 1 << EcmultGenWindowSize // 16
|
|
EcmultGenWindows = (256 + EcmultGenWindowSize - 1) / EcmultGenWindowSize // 64 windows
|
|
)
|
|
|
|
// EcmultContext holds precomputed tables for general scalar multiplication
|
|
type EcmultContext struct {
|
|
// Precomputed odd multiples: [1P, 3P, 5P, 7P, 9P, 11P, 13P, 15P]
|
|
// for each window position
|
|
preG [EcmultWindows][EcmultTableSize/2]GroupElementAffine
|
|
built bool
|
|
}
|
|
|
|
// EcmultGenContext holds precomputed tables for generator multiplication
|
|
// This is already defined in context.go, but let me enhance it
|
|
type EcmultGenContextEnhanced struct {
|
|
// Precomputed table: prec[i][j] = (j+1) * 2^(i*4) * G
|
|
// where G is the generator point
|
|
prec [EcmultGenWindows][EcmultGenTableSize]GroupElementAffine
|
|
blind GroupElementAffine // Blinding point for side-channel protection
|
|
built bool
|
|
}
|
|
|
|
// NewEcmultContext creates a new context for general scalar multiplication
|
|
func NewEcmultContext() *EcmultContext {
|
|
return &EcmultContext{built: false}
|
|
}
|
|
|
|
// Build builds the precomputed table for a given point
|
|
func (ctx *EcmultContext) Build(point *GroupElementAffine) error {
|
|
if ctx.built {
|
|
return nil
|
|
}
|
|
|
|
// Start with the base point
|
|
current := *point
|
|
|
|
// For each window position
|
|
for i := 0; i < EcmultWindows; i++ {
|
|
// Compute odd multiples: 1*current, 3*current, 5*current, ..., 15*current
|
|
ctx.preG[i][0] = current // 1 * current
|
|
|
|
// Compute 2*current for doubling
|
|
var double GroupElementJacobian
|
|
double.setGE(¤t)
|
|
double.double(&double)
|
|
var doubleAffine GroupElementAffine
|
|
doubleAffine.setGEJ(&double)
|
|
|
|
// Compute odd multiples by adding 2*current each time
|
|
for j := 1; j < EcmultTableSize/2; j++ {
|
|
var temp GroupElementJacobian
|
|
temp.setGE(&ctx.preG[i][j-1])
|
|
temp.addGE(&temp, &doubleAffine)
|
|
ctx.preG[i][j].setGEJ(&temp)
|
|
}
|
|
|
|
// Move to next window: current = 2^EcmultWindowSize * current
|
|
var temp GroupElementJacobian
|
|
temp.setGE(¤t)
|
|
for k := 0; k < EcmultWindowSize; k++ {
|
|
temp.double(&temp)
|
|
}
|
|
current.setGEJ(&temp)
|
|
}
|
|
|
|
ctx.built = true
|
|
return nil
|
|
}
|
|
|
|
// BuildGenerator builds the precomputed table for the generator point
|
|
func (ctx *EcmultGenContextEnhanced) BuildGenerator() error {
|
|
if ctx.built {
|
|
return nil
|
|
}
|
|
|
|
// Use the secp256k1 generator point
|
|
// G = (0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798,
|
|
// 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A6855419DC47D08FFB10D4B8)
|
|
|
|
var generator GroupElementAffine
|
|
generator = GeneratorAffine // Use our placeholder for now
|
|
|
|
// Initialize with proper generator coordinates
|
|
var gx, gy [32]byte
|
|
// Generator X coordinate
|
|
gx = [32]byte{
|
|
0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC,
|
|
0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07,
|
|
0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9,
|
|
0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98,
|
|
}
|
|
// Generator Y coordinate
|
|
gy = [32]byte{
|
|
0x48, 0x3A, 0xDA, 0x77, 0x26, 0xA3, 0xC4, 0x65,
|
|
0x5D, 0xA4, 0xFB, 0xFC, 0x0E, 0x11, 0x08, 0xA8,
|
|
0xFD, 0x17, 0xB4, 0x48, 0xA6, 0x85, 0x54, 0x19,
|
|
0x9C, 0x47, 0xD0, 0x8F, 0xFB, 0x10, 0xD4, 0xB8,
|
|
}
|
|
|
|
generator.x.setB32(gx[:])
|
|
generator.y.setB32(gy[:])
|
|
generator.x.normalize()
|
|
generator.y.normalize()
|
|
generator.infinity = false
|
|
|
|
// Build precomputed table
|
|
current := generator
|
|
|
|
// For each window position
|
|
for i := 0; i < EcmultGenWindows; i++ {
|
|
// First entry is the point at infinity (0 * current)
|
|
ctx.prec[i][0] = InfinityAffine
|
|
|
|
// Remaining entries are multiples: 1*current, 2*current, ..., 15*current
|
|
ctx.prec[i][1] = current
|
|
|
|
var temp GroupElementJacobian
|
|
temp.setGE(¤t)
|
|
|
|
for j := 2; j < EcmultGenTableSize; j++ {
|
|
temp.addGE(&temp, ¤t)
|
|
ctx.prec[i][j].setGEJ(&temp)
|
|
}
|
|
|
|
// Move to next window: current = 2^EcmultGenWindowSize * current
|
|
temp.setGE(¤t)
|
|
for k := 0; k < EcmultGenWindowSize; k++ {
|
|
temp.double(&temp)
|
|
}
|
|
current.setGEJ(&temp)
|
|
}
|
|
|
|
// Initialize blinding point to infinity
|
|
ctx.blind = InfinityAffine
|
|
ctx.built = true
|
|
return nil
|
|
}
|
|
|
|
// Ecmult performs scalar multiplication: r = a*G + b*P
|
|
// This is the main scalar multiplication function
|
|
func Ecmult(r *GroupElementJacobian, a *Scalar, b *Scalar, p *GroupElementAffine) {
|
|
// For now, use a simplified approach
|
|
// Real implementation would use Shamir's trick and precomputed tables
|
|
|
|
var aG, bP GroupElementJacobian
|
|
|
|
// Compute a*G using generator multiplication
|
|
if !a.isZero() {
|
|
EcmultGen(&aG, a)
|
|
} else {
|
|
aG.setInfinity()
|
|
}
|
|
|
|
// Compute b*P using general multiplication
|
|
if !b.isZero() && !p.infinity {
|
|
EcmultSimple(&bP, b, p)
|
|
} else {
|
|
bP.setInfinity()
|
|
}
|
|
|
|
// Add the results: r = aG + bP
|
|
r.addVar(&aG, &bP)
|
|
}
|
|
|
|
// EcmultGen performs optimized generator multiplication: r = a*G
|
|
func EcmultGen(r *GroupElementJacobian, a *Scalar) {
|
|
if a.isZero() {
|
|
r.setInfinity()
|
|
return
|
|
}
|
|
|
|
r.setInfinity()
|
|
|
|
// Process scalar in windows from most significant to least significant
|
|
for i := EcmultGenWindows - 1; i >= 0; i-- {
|
|
// Extract window bits
|
|
bits := a.getBits(uint(i*EcmultGenWindowSize), EcmultGenWindowSize)
|
|
|
|
if bits != 0 {
|
|
// Add precomputed point
|
|
// For now, use a simple approach since we don't have the full table
|
|
var temp GroupElementAffine
|
|
temp = GeneratorAffine // Placeholder
|
|
|
|
// Scale by appropriate power of 2
|
|
var scaled GroupElementJacobian
|
|
scaled.setGE(&temp)
|
|
for j := 0; j < i*EcmultGenWindowSize; j++ {
|
|
scaled.double(&scaled)
|
|
}
|
|
|
|
// Scale by the window value
|
|
for j := 1; j < int(bits); j++ {
|
|
scaled.addGE(&scaled, &temp)
|
|
}
|
|
|
|
r.addVar(r, &scaled)
|
|
}
|
|
}
|
|
}
|
|
|
|
// EcmultSimple performs simple scalar multiplication: r = k*P
|
|
func EcmultSimple(r *GroupElementJacobian, k *Scalar, p *GroupElementAffine) {
|
|
if k.isZero() || p.infinity {
|
|
r.setInfinity()
|
|
return
|
|
}
|
|
|
|
// Use binary method (double-and-add)
|
|
r.setInfinity()
|
|
|
|
// Start from most significant bit
|
|
for i := 255; i >= 0; i-- {
|
|
r.double(r)
|
|
|
|
if k.getBits(uint(i), 1) != 0 {
|
|
r.addGE(r, p)
|
|
}
|
|
}
|
|
}
|
|
|
|
// EcmultConst performs constant-time scalar multiplication: r = k*P
|
|
func EcmultConst(r *GroupElementJacobian, k *Scalar, p *GroupElementAffine) {
|
|
if k.isZero() || p.infinity {
|
|
r.setInfinity()
|
|
return
|
|
}
|
|
|
|
// Use windowed method with precomputed odd multiples
|
|
// Window size of 4 bits (16 precomputed points)
|
|
const windowSize = 4
|
|
const tableSize = 1 << windowSize // 16
|
|
|
|
// Precompute odd multiples: P, 3P, 5P, 7P, 9P, 11P, 13P, 15P
|
|
var table [tableSize/2]GroupElementAffine
|
|
table[0] = *p // 1P
|
|
|
|
// Compute 2P for doubling
|
|
var double GroupElementJacobian
|
|
double.setGE(p)
|
|
double.double(&double)
|
|
var doubleAffine GroupElementAffine
|
|
doubleAffine.setGEJ(&double)
|
|
|
|
// Compute odd multiples
|
|
for i := 1; i < tableSize/2; i++ {
|
|
var temp GroupElementJacobian
|
|
temp.setGE(&table[i-1])
|
|
temp.addGE(&temp, &doubleAffine)
|
|
table[i].setGEJ(&temp)
|
|
}
|
|
|
|
// Process scalar in windows
|
|
r.setInfinity()
|
|
|
|
for i := (256 + windowSize - 1) / windowSize - 1; i >= 0; i-- {
|
|
// Double for each bit in the window
|
|
for j := 0; j < windowSize; j++ {
|
|
r.double(r)
|
|
}
|
|
|
|
// Extract window bits
|
|
bits := k.getBits(uint(i*windowSize), windowSize)
|
|
|
|
if bits != 0 {
|
|
// Convert to odd form: if even, subtract 1 and set flag
|
|
var point GroupElementAffine
|
|
if bits&1 == 0 {
|
|
// Even: use (bits-1) and negate
|
|
point = table[(bits-1)/2]
|
|
point.negate(&point)
|
|
} else {
|
|
// Odd: use directly
|
|
point = table[bits/2]
|
|
}
|
|
|
|
r.addGE(r, &point)
|
|
}
|
|
}
|
|
}
|
|
|
|
// EcmultMulti performs multi-scalar multiplication: r = sum(k[i] * P[i])
|
|
func EcmultMulti(r *GroupElementJacobian, scalars []*Scalar, points []*GroupElementAffine) {
|
|
if len(scalars) != len(points) {
|
|
panic("scalars and points must have same length")
|
|
}
|
|
|
|
r.setInfinity()
|
|
|
|
// Simple approach: compute each k[i]*P[i] and add
|
|
for i := 0; i < len(scalars); i++ {
|
|
if !scalars[i].isZero() && !points[i].infinity {
|
|
var temp GroupElementJacobian
|
|
EcmultConst(&temp, scalars[i], points[i])
|
|
r.addVar(r, &temp)
|
|
}
|
|
}
|
|
}
|
|
|
|
// EcmultStrauss performs Strauss multi-scalar multiplication (more efficient)
|
|
func EcmultStrauss(r *GroupElementJacobian, scalars []*Scalar, points []*GroupElementAffine) {
|
|
if len(scalars) != len(points) {
|
|
panic("scalars and points must have same length")
|
|
}
|
|
|
|
// Use interleaved binary method for better efficiency
|
|
const windowSize = 4
|
|
|
|
r.setInfinity()
|
|
|
|
// Process all scalars bit by bit from MSB to LSB
|
|
for bitPos := 255; bitPos >= 0; bitPos-- {
|
|
r.double(r)
|
|
|
|
// Check each scalar's bit at this position
|
|
for i := 0; i < len(scalars); i++ {
|
|
if scalars[i].getBits(uint(bitPos), 1) != 0 {
|
|
r.addGE(r, points[i])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Blind applies blinding to a point for side-channel protection
|
|
func (ctx *EcmultGenContextEnhanced) Blind(seed []byte) error {
|
|
if !ctx.built {
|
|
return errors.New("context not built")
|
|
}
|
|
|
|
if seed == nil {
|
|
// Remove blinding
|
|
ctx.blind = InfinityAffine
|
|
return nil
|
|
}
|
|
|
|
// Generate blinding scalar from seed
|
|
var blindScalar Scalar
|
|
blindScalar.setB32(seed)
|
|
|
|
// Compute blinding point: blind = blindScalar * G
|
|
var blindPoint GroupElementJacobian
|
|
EcmultGen(&blindPoint, &blindScalar)
|
|
ctx.blind.setGEJ(&blindPoint)
|
|
|
|
return nil
|
|
}
|
|
|
|
// Clear clears the precomputed tables
|
|
func (ctx *EcmultContext) Clear() {
|
|
// Clear precomputed data
|
|
for i := range ctx.preG {
|
|
for j := range ctx.preG[i] {
|
|
ctx.preG[i][j].clear()
|
|
}
|
|
}
|
|
ctx.built = false
|
|
}
|
|
|
|
// Clear clears the generator context
|
|
func (ctx *EcmultGenContextEnhanced) Clear() {
|
|
// Clear precomputed data
|
|
for i := range ctx.prec {
|
|
for j := range ctx.prec[i] {
|
|
ctx.prec[i][j].clear()
|
|
}
|
|
}
|
|
ctx.blind.clear()
|
|
ctx.built = false
|
|
}
|
|
|
|
// GetTableSize returns the memory usage of precomputed tables
|
|
func (ctx *EcmultContext) GetTableSize() uintptr {
|
|
return unsafe.Sizeof(ctx.preG)
|
|
}
|
|
|
|
// GetTableSize returns the memory usage of generator tables
|
|
func (ctx *EcmultGenContextEnhanced) GetTableSize() uintptr {
|
|
return unsafe.Sizeof(ctx.prec) + unsafe.Sizeof(ctx.blind)
|
|
}
|
|
|
|
// Endomorphism optimization for secp256k1
|
|
// secp256k1 has an efficiently computable endomorphism that can split
|
|
// scalar multiplication into two half-size multiplications
|
|
|
|
// Lambda constant for secp256k1 endomorphism
|
|
var (
|
|
// λ = 0x5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72
|
|
Lambda = Scalar{
|
|
d: [4]uint64{
|
|
0xdf02967c1b23bd72,
|
|
0xa122e22ea2081667,
|
|
0xa5261c028812645a,
|
|
0x5363ad4cc05c30e0,
|
|
},
|
|
}
|
|
|
|
// β = 0x7ae96a2b657c07106e64479eac3434e99cf04975122f58995c1396c28719501e
|
|
Beta = FieldElement{
|
|
n: [5]uint64{
|
|
0x9cf04975122f5899, 0x5c1396c28719501e, 0x6e64479eac3434e9,
|
|
0x7ae96a2b657c0710, 0x0000000000000000,
|
|
},
|
|
magnitude: 1,
|
|
normalized: true,
|
|
}
|
|
)
|
|
|
|
// SplitLambda splits a scalar k into k1, k2 such that k = k1 + k2*λ
|
|
// where k1, k2 are approximately half the bit length of k
|
|
func (k *Scalar) SplitLambda() (k1, k2 Scalar, neg1, neg2 bool) {
|
|
// This is a simplified implementation
|
|
// Real implementation uses Babai's nearest plane algorithm
|
|
|
|
// For now, use a simple approach
|
|
k1 = *k
|
|
k2.setInt(0)
|
|
neg1 = false
|
|
neg2 = false
|
|
|
|
// TODO: Implement proper lambda splitting
|
|
return k1, k2, neg1, neg2
|
|
}
|
|
|
|
// EcmultEndomorphism performs scalar multiplication using endomorphism
|
|
func EcmultEndomorphism(r *GroupElementJacobian, k *Scalar, p *GroupElementAffine) {
|
|
if k.isZero() || p.infinity {
|
|
r.setInfinity()
|
|
return
|
|
}
|
|
|
|
// Split scalar using endomorphism
|
|
k1, k2, neg1, neg2 := k.SplitLambda()
|
|
|
|
// Compute β*P (endomorphism of P)
|
|
var betaP GroupElementAffine
|
|
betaP.x.mul(&p.x, &Beta)
|
|
betaP.y = p.y
|
|
betaP.infinity = p.infinity
|
|
|
|
// Compute k1*P and k2*(β*P) simultaneously using Shamir's trick
|
|
var points [2]*GroupElementAffine
|
|
var scalars [2]*Scalar
|
|
|
|
points[0] = p
|
|
points[1] = &betaP
|
|
scalars[0] = &k1
|
|
scalars[1] = &k2
|
|
|
|
// Apply negations if needed
|
|
if neg1 {
|
|
scalars[0].negate(scalars[0])
|
|
}
|
|
if neg2 {
|
|
scalars[1].negate(scalars[1])
|
|
}
|
|
|
|
// Use Strauss method for dual multiplication
|
|
EcmultStrauss(r, scalars[:], points[:])
|
|
|
|
// Apply final negation if needed
|
|
if neg1 {
|
|
r.negate(r)
|
|
}
|
|
}
|