mirror of
https://github.com/luxfi/crypto.git
synced 2026-07-27 01:54:50 +00:00
Replace github.com/luxfi/crypto/ipa/banderwagon with the canonical github.com/luxfi/crypto/banderwagon in ipa/batch.go and its test, plus the verkle-ipa docs example and the rust spec_vectors comment. The old ipa/banderwagon subdirectory was deleted in 222f3d8; banderwagon now has a single canonical home at the top level of luxfi/crypto. go.mod adds the indirect entries for go-verkle and go-ipa that the rerouted test_helper graph now exercises. The luxfi-mirror replace directives remain in place so all upstream go-ipa/go-verkle traffic still flows through luxfi-maintained sources. Build: go build ./... clean (one ld linker warning unrelated). Tests: ./banderwagon/... ./ipa/... pass (7 ok, 2 no-test-files). Pre-existing failure in ./verkle/ is unrelated: verkle_test.go references BatchProof/VerifyBatch/ErrBatchLengthMismatch symbols that were never implemented in the verkle package (separate gap, present on main before this fix).
469 lines
10 KiB
Plaintext
469 lines
10 KiB
Plaintext
---
|
|
title: Inner Product Arguments (IPA) & Verkle Trees
|
|
description: Cryptographic primitives for Verkle tree state commitments and proofs
|
|
---
|
|
|
|
# Inner Product Arguments (IPA) & Verkle Trees
|
|
|
|
IPA (Inner Product Arguments) provide the cryptographic foundation for Verkle trees, enabling efficient state proofs with smaller proof sizes than Merkle Patricia Trees.
|
|
|
|
## Overview
|
|
|
|
Verkle trees with IPA provide:
|
|
|
|
- **Smaller Proofs**: ~150 bytes vs ~1 KB for Merkle proofs
|
|
- **Efficient Updates**: O(log n) complexity for state updates
|
|
- **Constant Verification**: Fixed verification cost regardless of tree depth
|
|
- **State Commitment**: Compact commitment to entire blockchain state
|
|
|
|
## Technical Details
|
|
|
|
### Bandersnatch Curve
|
|
|
|
The implementation uses the Bandersnatch curve:
|
|
|
|
| Parameter | Value |
|
|
|-----------|-------|
|
|
| Curve | Bandersnatch (embedded in BLS12-381) |
|
|
| Field Size | 253 bits |
|
|
| Group Order | ~2^253 |
|
|
| Security Level | 128 bits |
|
|
|
|
### IPA Parameters
|
|
|
|
| Parameter | Value |
|
|
|-----------|-------|
|
|
| Vector Length | 256 |
|
|
| Number of Rounds | 8 (log2(256)) |
|
|
| Commitment Size | 32 bytes |
|
|
| Proof Size | ~544 bytes |
|
|
|
|
## Implementation
|
|
|
|
### Setting Up IPA
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/luxfi/crypto/ipa/ipa"
|
|
"github.com/luxfi/crypto/banderwagon"
|
|
"github.com/luxfi/crypto/ipa/bandersnatch/fr"
|
|
)
|
|
|
|
func main() {
|
|
// Initialize IPA settings (generates SRS)
|
|
config, err := ipa.NewIPASettings()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Printf("SRS contains %d points\n", len(config.SRS))
|
|
fmt.Printf("Number of rounds: %d\n", config.NumRounds())
|
|
}
|
|
```
|
|
|
|
### Pedersen Commitments
|
|
|
|
Create commitments to polynomials:
|
|
|
|
```go
|
|
func commitToPolynomial(config *ipa.IPAConfig, polynomial []fr.Element) banderwagon.Element {
|
|
// Commit using precomputed MSM
|
|
commitment := config.Commit(polynomial)
|
|
|
|
fmt.Printf("Commitment: %x\n", commitment.Bytes())
|
|
return commitment
|
|
}
|
|
|
|
// Create polynomial from data
|
|
func createPolynomial(data []byte) []fr.Element {
|
|
poly := make([]fr.Element, 256)
|
|
|
|
for i := 0; i < len(data) && i < 256; i++ {
|
|
poly[i].SetUint64(uint64(data[i]))
|
|
}
|
|
|
|
return poly
|
|
}
|
|
```
|
|
|
|
### Inner Product Computation
|
|
|
|
Compute inner products of vectors:
|
|
|
|
```go
|
|
func computeInnerProduct(a, b []fr.Element) (fr.Element, error) {
|
|
if len(a) != len(b) {
|
|
return fr.Element{}, errors.New("vectors must have same length")
|
|
}
|
|
|
|
result, err := ipa.InnerProd(a, b)
|
|
if err != nil {
|
|
return fr.Element{}, err
|
|
}
|
|
|
|
fmt.Printf("Inner product: %s\n", result.String())
|
|
return result, nil
|
|
}
|
|
```
|
|
|
|
### Multi-Scalar Multiplication
|
|
|
|
Efficient MSM for group operations:
|
|
|
|
```go
|
|
func multiScalarMult(points []banderwagon.Element, scalars []fr.Element) (banderwagon.Element, error) {
|
|
result, err := ipa.MultiScalar(points, scalars)
|
|
if err != nil {
|
|
return banderwagon.Element{}, err
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
```
|
|
|
|
## Verkle Tree Structure
|
|
|
|
### Node Types
|
|
|
|
```go
|
|
type VerkleNode interface {
|
|
Commitment() banderwagon.Element
|
|
Hash() []byte
|
|
}
|
|
|
|
type InternalNode struct {
|
|
children [256]VerkleNode
|
|
commitment banderwagon.Element
|
|
}
|
|
|
|
type LeafNode struct {
|
|
stem [31]byte
|
|
values [256][]byte
|
|
commitment banderwagon.Element
|
|
}
|
|
|
|
type EmptyNode struct{}
|
|
```
|
|
|
|
### Tree Operations
|
|
|
|
```go
|
|
type VerkleTree struct {
|
|
root VerkleNode
|
|
config *ipa.IPAConfig
|
|
}
|
|
|
|
func NewVerkleTree(config *ipa.IPAConfig) *VerkleTree {
|
|
return &VerkleTree{
|
|
root: &EmptyNode{},
|
|
config: config,
|
|
}
|
|
}
|
|
|
|
// Insert a key-value pair
|
|
func (t *VerkleTree) Insert(key []byte, value []byte) error {
|
|
stem := key[:31]
|
|
suffix := key[31]
|
|
|
|
// Navigate to leaf, creating nodes as needed
|
|
// Update commitments along the path
|
|
|
|
return nil
|
|
}
|
|
|
|
// Get a value by key
|
|
func (t *VerkleTree) Get(key []byte) ([]byte, error) {
|
|
stem := key[:31]
|
|
suffix := key[31]
|
|
|
|
// Navigate to leaf
|
|
// Return value at suffix position
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
// Generate proof for a key
|
|
func (t *VerkleTree) Prove(key []byte) (*VerkleProof, error) {
|
|
// Generate IPA proof for the path
|
|
|
|
return nil, nil
|
|
}
|
|
```
|
|
|
|
## IPA Proof Generation
|
|
|
|
### Prover
|
|
|
|
```go
|
|
type IPAProver struct {
|
|
config *ipa.IPAConfig
|
|
}
|
|
|
|
func (p *IPAProver) CreateProof(
|
|
commitment banderwagon.Element,
|
|
polynomial []fr.Element,
|
|
point fr.Element,
|
|
) (*IPAProof, error) {
|
|
// Generate IPA proof that polynomial evaluates to
|
|
// a specific value at the given point
|
|
|
|
proof := &IPAProof{
|
|
L: make([]banderwagon.Element, p.config.NumRounds()),
|
|
R: make([]banderwagon.Element, p.config.NumRounds()),
|
|
}
|
|
|
|
// Prover algorithm:
|
|
// 1. Split vectors in half
|
|
// 2. Compute cross terms L and R
|
|
// 3. Get challenge from verifier (Fiat-Shamir)
|
|
// 4. Fold vectors
|
|
// 5. Repeat for log(n) rounds
|
|
|
|
return proof, nil
|
|
}
|
|
|
|
type IPAProof struct {
|
|
L []banderwagon.Element // Left cross terms
|
|
R []banderwagon.Element // Right cross terms
|
|
A fr.Element // Final scalar
|
|
}
|
|
```
|
|
|
|
### Verifier
|
|
|
|
```go
|
|
type IPAVerifier struct {
|
|
config *ipa.IPAConfig
|
|
}
|
|
|
|
func (v *IPAVerifier) VerifyProof(
|
|
commitment banderwagon.Element,
|
|
point fr.Element,
|
|
evaluation fr.Element,
|
|
proof *IPAProof,
|
|
) bool {
|
|
// Verify IPA proof
|
|
|
|
// Verifier algorithm:
|
|
// 1. Recompute challenges from L, R values
|
|
// 2. Compute final commitment
|
|
// 3. Check against claimed evaluation
|
|
|
|
return true
|
|
}
|
|
```
|
|
|
|
## Multi-Proof System
|
|
|
|
Efficient proofs for multiple keys:
|
|
|
|
```go
|
|
type MultiProof struct {
|
|
D banderwagon.Element // Commitment to quotient polynomial
|
|
IPAProof *IPAProof // IPA proof for evaluation
|
|
ClaimedValues []fr.Element // Values at queried positions
|
|
}
|
|
|
|
func CreateMultiProof(
|
|
config *ipa.IPAConfig,
|
|
commitments []banderwagon.Element,
|
|
polynomials [][]fr.Element,
|
|
points []fr.Element,
|
|
) (*MultiProof, error) {
|
|
// Create proof for multiple polynomial evaluations
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
func VerifyMultiProof(
|
|
config *ipa.IPAConfig,
|
|
commitments []banderwagon.Element,
|
|
points []fr.Element,
|
|
values []fr.Element,
|
|
proof *MultiProof,
|
|
) bool {
|
|
// Verify multi-proof
|
|
|
|
return true
|
|
}
|
|
```
|
|
|
|
## State Management
|
|
|
|
### State Commitment
|
|
|
|
```go
|
|
type StateCommitment struct {
|
|
Root banderwagon.Element
|
|
BlockNum uint64
|
|
StateRoot []byte
|
|
}
|
|
|
|
func (s *StateCommitment) Update(changes map[string][]byte) (*StateCommitment, error) {
|
|
// Apply changes to state tree
|
|
// Recompute affected commitments
|
|
// Return new state commitment
|
|
|
|
return nil, nil
|
|
}
|
|
```
|
|
|
|
### Witness Generation
|
|
|
|
```go
|
|
type ExecutionWitness struct {
|
|
StateDiff []KeyValuePair
|
|
VerkleProof *MultiProof
|
|
ParentState []byte
|
|
}
|
|
|
|
func GenerateWitness(
|
|
tree *VerkleTree,
|
|
accessedKeys [][]byte,
|
|
) (*ExecutionWitness, error) {
|
|
// Generate witness for accessed state
|
|
|
|
return nil, nil
|
|
}
|
|
```
|
|
|
|
## Performance Benchmarks
|
|
|
|
| Operation | Time | Notes |
|
|
|-----------|------|-------|
|
|
| Commit (256 values) | 2.5 ms | Using precomputed MSM |
|
|
| IPA Prove | 15 ms | 8 rounds |
|
|
| IPA Verify | 8 ms | Single proof |
|
|
| Multi-proof (100 keys) | 150 ms | Batched |
|
|
| Multi-verify (100 keys) | 50 ms | Batched |
|
|
|
|
### Proof Sizes
|
|
|
|
| Proof Type | Size |
|
|
|------------|------|
|
|
| Single IPA proof | 544 bytes |
|
|
| Verkle proof (depth 4) | ~600 bytes |
|
|
| Multi-proof (10 keys) | ~1.5 KB |
|
|
| Multi-proof (100 keys) | ~3 KB |
|
|
|
|
## Comparison with Merkle Trees
|
|
|
|
| Aspect | Merkle Patricia | Verkle |
|
|
|--------|-----------------|--------|
|
|
| Proof size | ~1-3 KB | ~150-600 bytes |
|
|
| Update complexity | O(log n) | O(log n) |
|
|
| Verification | O(log n) hashes | O(1) pairings |
|
|
| Witness size | Large | Small |
|
|
| Statelessness | Difficult | Feasible |
|
|
|
|
## Security Properties
|
|
|
|
### Binding
|
|
|
|
```go
|
|
// Commitments are computationally binding
|
|
// Cannot find two different polynomials with same commitment
|
|
func demonstrateBinding() {
|
|
config, _ := ipa.NewIPASettings()
|
|
|
|
poly1 := make([]fr.Element, 256)
|
|
poly2 := make([]fr.Element, 256)
|
|
|
|
poly1[0].SetUint64(1)
|
|
poly2[0].SetUint64(2)
|
|
|
|
c1 := config.Commit(poly1)
|
|
c2 := config.Commit(poly2)
|
|
|
|
// c1 != c2 with overwhelming probability
|
|
}
|
|
```
|
|
|
|
### Soundness
|
|
|
|
```go
|
|
// Cannot create valid proof for incorrect evaluation
|
|
// Soundness relies on discrete log hardness in Bandersnatch
|
|
func testSoundness(t *testing.T) {
|
|
// Create proof for correct evaluation
|
|
// Try to verify with wrong evaluation value
|
|
// Must fail
|
|
|
|
require.False(t, verifier.VerifyProof(commitment, point, wrongValue, proof))
|
|
}
|
|
```
|
|
|
|
## Integration with Lux
|
|
|
|
### Block State Root
|
|
|
|
```go
|
|
type LuxBlock struct {
|
|
Header *BlockHeader
|
|
Transactions []*Transaction
|
|
VerkleRoot banderwagon.Element
|
|
}
|
|
|
|
func (b *LuxBlock) ComputeStateRoot(tree *VerkleTree) {
|
|
b.VerkleRoot = tree.root.Commitment()
|
|
}
|
|
```
|
|
|
|
### Stateless Validation
|
|
|
|
```go
|
|
type StatelessValidator struct {
|
|
config *ipa.IPAConfig
|
|
}
|
|
|
|
func (v *StatelessValidator) ValidateBlock(
|
|
block *LuxBlock,
|
|
witness *ExecutionWitness,
|
|
) error {
|
|
// Verify witness against parent state
|
|
// Execute transactions using witness data
|
|
// Verify resulting state matches block state root
|
|
|
|
return nil
|
|
}
|
|
```
|
|
|
|
## Testing
|
|
|
|
```go
|
|
func TestIPACommitment(t *testing.T) {
|
|
config, err := ipa.NewIPASettings()
|
|
require.NoError(t, err)
|
|
|
|
// Create polynomial
|
|
poly := make([]fr.Element, 256)
|
|
for i := 0; i < 256; i++ {
|
|
poly[i].SetUint64(uint64(i))
|
|
}
|
|
|
|
// Commit
|
|
commitment := config.Commit(poly)
|
|
require.False(t, commitment.IsIdentity())
|
|
|
|
// Same polynomial should give same commitment
|
|
commitment2 := config.Commit(poly)
|
|
require.True(t, commitment.Equal(&commitment2))
|
|
|
|
// Different polynomial should give different commitment
|
|
poly[0].SetUint64(999)
|
|
commitment3 := config.Commit(poly)
|
|
require.False(t, commitment.Equal(&commitment3))
|
|
}
|
|
```
|
|
|
|
## References
|
|
|
|
- [Verkle Trees](https://vitalik.ca/general/2021/06/18/verkle.html)
|
|
- [Inner Product Arguments](https://eprint.iacr.org/2019/1021)
|
|
- [Bandersnatch Curve](https://eprint.iacr.org/2021/1152)
|
|
- [go-verkle Implementation](https://github.com/ethereum/go-verkle)
|
|
- [EIP-6800: Ethereum state using a Verkle tree](https://eips.ethereum.org/EIPS/eip-6800)
|