Remove deprecated files and update README to reflect current implementation status and features. This commit deletes unused context, ecmult, and test files, streamlining the codebase. The README has been revised to include architectural details, performance benchmarks, and security considerations for the secp256k1 implementation.
This commit is contained in:
297
context.go
Normal file
297
context.go
Normal file
@@ -0,0 +1,297 @@
|
||||
package p256k1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Context represents a secp256k1 context object that holds randomization data
|
||||
// and callback functions for enhanced protection against side-channel leakage
|
||||
type Context struct {
|
||||
ecmultGenCtx EcmultGenContext
|
||||
illegalCallback Callback
|
||||
errorCallback Callback
|
||||
declassify bool
|
||||
}
|
||||
|
||||
// EcmultGenContext holds precomputed data for scalar multiplication with the generator
|
||||
type EcmultGenContext struct {
|
||||
built bool
|
||||
// Precomputed table: prec[i][j] = (j+1) * 2^(i*4) * G
|
||||
prec [64][16]GroupElementAffine
|
||||
blindPoint GroupElementAffine // Blinding point for side-channel protection
|
||||
}
|
||||
|
||||
// Context flags
|
||||
const (
|
||||
ContextNone = 0x01
|
||||
ContextVerify = 0x01 | 0x0100 // Deprecated, treated as NONE
|
||||
ContextSign = 0x01 | 0x0200 // Deprecated, treated as NONE
|
||||
ContextDeclassify = 0x01 | 0x0400 // Testing flag
|
||||
)
|
||||
|
||||
// Static context for basic operations (limited functionality)
|
||||
var ContextStatic = &Context{
|
||||
ecmultGenCtx: EcmultGenContext{built: false},
|
||||
illegalCallback: defaultIllegalCallback,
|
||||
errorCallback: defaultErrorCallback,
|
||||
declassify: false,
|
||||
}
|
||||
|
||||
// ContextCreate creates a new secp256k1 context object
|
||||
func ContextCreate(flags uint) (ctx *Context, err error) {
|
||||
// Validate flags
|
||||
if (flags & 0xFF) != ContextNone {
|
||||
return nil, errors.New("invalid flags")
|
||||
}
|
||||
|
||||
ctx = &Context{
|
||||
illegalCallback: defaultIllegalCallback,
|
||||
errorCallback: defaultErrorCallback,
|
||||
declassify: (flags & ContextDeclassify) != 0,
|
||||
}
|
||||
|
||||
// Build the ecmult_gen context
|
||||
err = ctx.ecmultGenCtx.build()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
// ContextClone creates a copy of a context
|
||||
func ContextClone(ctx *Context) (newCtx *Context, err error) {
|
||||
if ctx == ContextStatic {
|
||||
return nil, errors.New("cannot clone static context")
|
||||
}
|
||||
|
||||
newCtx = &Context{
|
||||
ecmultGenCtx: ctx.ecmultGenCtx,
|
||||
illegalCallback: ctx.illegalCallback,
|
||||
errorCallback: ctx.errorCallback,
|
||||
declassify: ctx.declassify,
|
||||
}
|
||||
|
||||
return newCtx, nil
|
||||
}
|
||||
|
||||
// ContextDestroy destroys a context object
|
||||
func ContextDestroy(ctx *Context) {
|
||||
if ctx == nil || ctx == ContextStatic {
|
||||
return
|
||||
}
|
||||
|
||||
ctx.ecmultGenCtx.clear()
|
||||
ctx.illegalCallback = Callback{}
|
||||
ctx.errorCallback = Callback{}
|
||||
}
|
||||
|
||||
// ContextSetIllegalCallback sets the illegal argument callback
|
||||
func ContextSetIllegalCallback(ctx *Context, fn func(string, interface{}), data interface{}) error {
|
||||
if ctx == ContextStatic {
|
||||
return errors.New("cannot set callback on static context")
|
||||
}
|
||||
|
||||
if fn == nil {
|
||||
ctx.illegalCallback = defaultIllegalCallback
|
||||
} else {
|
||||
ctx.illegalCallback = Callback{Fn: fn, Data: data}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextSetErrorCallback sets the error callback
|
||||
func ContextSetErrorCallback(ctx *Context, fn func(string, interface{}), data interface{}) error {
|
||||
if ctx == ContextStatic {
|
||||
return errors.New("cannot set callback on static context")
|
||||
}
|
||||
|
||||
if fn == nil {
|
||||
ctx.errorCallback = defaultErrorCallback
|
||||
} else {
|
||||
ctx.errorCallback = Callback{Fn: fn, Data: data}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextRandomize randomizes the context for enhanced side-channel protection
|
||||
func ContextRandomize(ctx *Context, seed32 []byte) error {
|
||||
if ctx == ContextStatic {
|
||||
return errors.New("cannot randomize static context")
|
||||
}
|
||||
|
||||
if !ctx.ecmultGenCtx.built {
|
||||
return errors.New("context not properly initialized")
|
||||
}
|
||||
|
||||
if seed32 != nil && len(seed32) != 32 {
|
||||
return errors.New("seed must be 32 bytes or nil")
|
||||
}
|
||||
|
||||
// Apply randomization to the ecmult_gen context
|
||||
return ctx.ecmultGenCtx.blind(seed32)
|
||||
}
|
||||
|
||||
// isProper checks if a context is proper (not static and properly initialized)
|
||||
func (ctx *Context) isProper() bool {
|
||||
return ctx != ContextStatic && ctx.ecmultGenCtx.built
|
||||
}
|
||||
|
||||
// EcmultGenContext methods
|
||||
|
||||
// build initializes the ecmult_gen context with precomputed values
|
||||
func (ctx *EcmultGenContext) build() error {
|
||||
if ctx.built {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Initialize with proper generator coordinates
|
||||
var generator GroupElementAffine
|
||||
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 for optimized generator multiplication
|
||||
current := generator
|
||||
|
||||
// For each window position (64 windows of 4 bits each)
|
||||
for i := 0; i < 64; i++ {
|
||||
// First entry is 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 < 16; j++ {
|
||||
temp.addGE(&temp, ¤t)
|
||||
ctx.prec[i][j].setGEJ(&temp)
|
||||
}
|
||||
|
||||
// Move to next window: current = 2^4 * current = 16 * current
|
||||
temp.setGE(¤t)
|
||||
for k := 0; k < 4; k++ {
|
||||
temp.double(&temp)
|
||||
}
|
||||
current.setGEJ(&temp)
|
||||
}
|
||||
|
||||
// Initialize blinding point to infinity
|
||||
ctx.blindPoint = InfinityAffine
|
||||
ctx.built = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// clear clears the ecmult_gen context
|
||||
func (ctx *EcmultGenContext) clear() {
|
||||
// Clear precomputed data
|
||||
for i := range ctx.prec {
|
||||
for j := range ctx.prec[i] {
|
||||
ctx.prec[i][j].clear()
|
||||
}
|
||||
}
|
||||
ctx.blindPoint.clear()
|
||||
ctx.built = false
|
||||
}
|
||||
|
||||
// blind applies blinding to the precomputed table for side-channel protection
|
||||
func (ctx *EcmultGenContext) blind(seed32 []byte) error {
|
||||
if !ctx.built {
|
||||
return errors.New("context not built")
|
||||
}
|
||||
|
||||
var blindingFactor Scalar
|
||||
|
||||
if seed32 == nil {
|
||||
// Remove blinding
|
||||
ctx.blindPoint = InfinityAffine
|
||||
return nil
|
||||
} else {
|
||||
blindingFactor.setB32(seed32)
|
||||
}
|
||||
|
||||
// Apply blinding to precomputed table
|
||||
// This is a simplified implementation - real version needs proper blinding
|
||||
|
||||
// For now, just mark as blinded (actual blinding is complex)
|
||||
return nil
|
||||
}
|
||||
|
||||
// isBuilt returns true if the ecmult_gen context is built
|
||||
func (ctx *EcmultGenContext) isBuilt() bool {
|
||||
return ctx.built
|
||||
}
|
||||
|
||||
// Selftest performs basic self-tests to detect serious usage errors
|
||||
func Selftest() error {
|
||||
// Test basic field operations
|
||||
var a, b, c FieldElement
|
||||
a.setInt(1)
|
||||
b.setInt(2)
|
||||
c.add(&a)
|
||||
c.add(&b)
|
||||
c.normalize()
|
||||
|
||||
var expected FieldElement
|
||||
expected.setInt(3)
|
||||
expected.normalize()
|
||||
|
||||
if !c.equal(&expected) {
|
||||
return errors.New("field addition self-test failed")
|
||||
}
|
||||
|
||||
// Test basic scalar operations
|
||||
var sa, sb, sc Scalar
|
||||
sa.setInt(2)
|
||||
sb.setInt(3)
|
||||
sc.mul(&sa, &sb)
|
||||
|
||||
var sexpected Scalar
|
||||
sexpected.setInt(6)
|
||||
|
||||
if !sc.equal(&sexpected) {
|
||||
return errors.New("scalar multiplication self-test failed")
|
||||
}
|
||||
|
||||
// Test point operations
|
||||
var p GroupElementAffine
|
||||
p = GeneratorAffine
|
||||
|
||||
if !p.isValid() {
|
||||
return errors.New("generator point validation failed")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// declassifyMem marks memory as no-longer-secret for constant-time analysis
|
||||
func (ctx *Context) declassifyMem(ptr unsafe.Pointer, len uintptr) {
|
||||
if ctx.declassify {
|
||||
// In a real implementation, this would call memory analysis tools
|
||||
// For now, this is a no-op
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user