Skip to content

Commit f755d00

Browse files
committed
QoL improvements
1 parent 12f8f7a commit f755d00

File tree

12 files changed

+450
-95
lines changed

12 files changed

+450
-95
lines changed

blind-auction/ibf.go

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@ func ChunkToElement(data [IBFChunkSize]byte) *big.Int {
8080

8181
// ElementToChunk converts a field element back to a chunk, preserving leading zeros.
8282
func ElementToChunk(el *big.Int) [IBFChunkSize]byte {
83-
var data [IBFChunkSize]byte
84-
el.FillBytes(data[:])
85-
return data
83+
var data [IBFChunkSize]byte
84+
el.FillBytes(data[:])
85+
return data
8686
}
8787

8888
// InsertChunk adds a chunk to the IBF using field addition in AuctionFieldOrder.
@@ -218,19 +218,19 @@ func (v *IBFVector) Recover() ([][IBFChunkSize]byte, error) {
218218

219219
// Bytes serializes the IBF to a byte slice.
220220
func (v *IBFVector) Bytes() []byte {
221-
res := binary.BigEndian.AppendUint32([]byte{}, uint32(len(v.Chunks)))
222-
res = binary.BigEndian.AppendUint32(res, uint32(len(v.Chunks[0])))
223-
for level := range v.Chunks {
224-
for chunk := range v.Chunks[level] {
225-
res = append(res, v.Chunks[level][chunk][:]...)
226-
}
227-
}
228-
229-
for level := range v.Counters {
230-
for i := range v.Counters[level] {
231-
res = binary.BigEndian.AppendUint64(res, v.Counters[level][i])
232-
}
233-
}
234-
235-
return res
221+
res := binary.BigEndian.AppendUint32([]byte{}, uint32(len(v.Chunks)))
222+
res = binary.BigEndian.AppendUint32(res, uint32(len(v.Chunks[0])))
223+
for level := range v.Chunks {
224+
for chunk := range v.Chunks[level] {
225+
res = append(res, v.Chunks[level][chunk][:]...)
226+
}
227+
}
228+
229+
for level := range v.Counters {
230+
for i := range v.Counters[level] {
231+
res = binary.BigEndian.AppendUint64(res, v.Counters[level][i])
232+
}
233+
}
234+
235+
return res
236236
}

blind-auction/ibf_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ func TestIBFUnion(t *testing.T) {
7474
ibf1els := ibf1.EncodeAsFieldElements()
7575
ibf2els := ibf2.EncodeAsFieldElements()
7676

77-
7877
// Combine the IBFs
7978
combined := ibf1els
8079
for i := range ibf2els {

crypto/doc.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,18 @@
1313
// protocol implementations.
1414
// Note: not all cryptographic operations are constant-time (in particular field and polynomial math)
1515
//
16-
// Field Operations
16+
// # Field Operations
1717
//
1818
// The package supports operations in two finite fields:
1919
// - MessageFieldOrder: A 513-bit field for encoding 512-bit message chunks
2020
// - AuctionFieldOrder: A 384-bit field for auction-related operations
2121
//
22-
// Secret Sharing
22+
// # Secret Sharing
2323
//
2424
// Polynomial-based secret sharing is implemented using Neville interpolation,
2525
// allowing efficient reconstruction of secrets from threshold shares.
2626
//
27-
// Key Management
27+
// # Key Management
2828
//
2929
// The package provides Ed25519 for signing operations and X25519 for key exchange.
3030
// All keys include helper methods for serialization and comparison.

crypto/fields.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@ func FieldAddInplace(l *big.Int, r *big.Int, fieldOrder *big.Int) *big.Int {
2626
l.Add(l, r)
2727
l.Mod(l, fieldOrder)
2828
/*
29-
for l.Cmp(fieldOrder) > 1 {
30-
l = l.Sub(l, fieldOrder)
31-
}
32-
for l.Sign() < 0 {
33-
l = l.Add(l, fieldOrder)
34-
}
29+
for l.Cmp(fieldOrder) > 1 {
30+
l = l.Sub(l, fieldOrder)
31+
}
32+
for l.Sign() < 0 {
33+
l = l.Add(l, fieldOrder)
34+
}
3535
*/
3636
return l
3737
}
@@ -43,11 +43,11 @@ func FieldSubInplace(l *big.Int, r *big.Int, fieldOrder *big.Int) *big.Int {
4343
l.Sub(l, r)
4444
l.Mod(l, fieldOrder)
4545
/*
46-
for l.Sign() < 0 {
47-
l.Add(l, fieldOrder)
48-
}
49-
for l.Cmp(fieldOrder) > 1 {
50-
l.Sub(l, fieldOrder)
51-
}*/
46+
for l.Sign() < 0 {
47+
l.Add(l, fieldOrder)
48+
}
49+
for l.Cmp(fieldOrder) > 1 {
50+
l.Sub(l, fieldOrder)
51+
}*/
5252
return l
5353
}

crypto/polynomials.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func NevilleInterpolation(xs []*big.Int, ys []*big.Int, x *big.Int, fieldOrder *
3939
ps[i].Denom().Mul(ps[i].Denom(), dm.Sub(xs[i], xs[i+k]))
4040
}
4141
}
42-
42+
4343
// Convert rational result to field element: (num * denom^-1) mod fieldOrder
4444
result := new(big.Int).Set(ps[0].Num())
4545
denomInv := new(big.Int).ModInverse(ps[0].Denom(), fieldOrder)
@@ -52,7 +52,7 @@ func NevilleInterpolation(xs []*big.Int, ys []*big.Int, x *big.Int, fieldOrder *
5252

5353
// DeriveBlindingVector deterministically generates a vector of blinding elements from shared secrets for the given round.
5454
func DeriveBlindingVector(sharedSecrets []SharedKey, round uint32, nEls int32, fieldOrder *big.Int) []*big.Int {
55-
bytesPerElement := (fieldOrder.BitLen()+7)/8
55+
bytesPerElement := (fieldOrder.BitLen() + 7) / 8
5656
srcBytesBuf := make([]byte, int(nEls)*bytesPerElement)
5757
dstBytesBuf := make([]byte, int(nEls)*bytesPerElement)
5858
elBuf := make([]big.Int, nEls)
@@ -63,23 +63,24 @@ func DeriveBlindingVector(sharedSecrets []SharedKey, round uint32, nEls int32, f
6363

6464
// Assumes all shared secrets are the same length
6565
roundKeyBuf := make([]byte, 4+len(sharedSecrets[0]))
66-
binary.BigEndian.PutUint32(roundKeyBuf[:4], uint32(round))
66+
binary.BigEndian.PutUint32(roundKeyBuf[:4], uint32(round))
6767

6868
workingEl := big.NewInt(0)
6969

7070
for _, sharedSecret := range sharedSecrets {
7171
copy(roundKeyBuf[4:], sharedSecret)
7272
roundSharedKey := sha3.Sum256(roundKeyBuf)
7373

74-
block, err := aes.NewCipher(roundSharedKey[:])
74+
// 128 bit AES
75+
block, err := aes.NewCipher(roundSharedKey[:16])
7576
if err != nil {
7677
panic(err.Error())
7778
}
7879

7980
block.Encrypt(dstBytesBuf, srcBytesBuf)
8081

8182
for i := 0; i < int(nEls); i++ {
82-
workingEl.SetBytes(dstBytesBuf[i*bytesPerElement:(i+1)*bytesPerElement])
83+
workingEl.SetBytes(dstBytesBuf[i*bytesPerElement : (i+1)*bytesPerElement])
8384
FieldAddInplace(res[i], workingEl, fieldOrder)
8485
}
8586
}

crypto/polynomials_test.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package crypto
22

33
import (
4-
"math/big"
54
"crypto/rand"
5+
"math/big"
66
unsafe_rand "math/rand"
77
"testing"
88

@@ -145,5 +145,3 @@ func TestServerStreams(t *testing.T) {
145145

146146
require.Zero(t, NevilleInterpolation(bigOneTwoThree[:2], []*big.Int{s0Vector[0], s1Vector[0]}, big.NewInt(0), MessageFieldOrder).Cmp(m0))
147147
}
148-
149-

protocol/doc.go

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,23 +23,23 @@
2323
// # Core Protocol Flow
2424
//
2525
// 1. Message Preparation (Client):
26-
// - Client determines if it won a slot in the previous round's auction
27-
// - Encodes message and auction data as field elements
28-
// - Creates polynomial shares using Shamir secret sharing (degree t-1 for t threshold)
29-
// - Blinds each share with server-specific one-time pads
26+
// - Client determines if it won a slot in the previous round's auction
27+
// - Encodes message and auction data as field elements
28+
// - Creates polynomial shares using Shamir secret sharing (degree t-1 for t threshold)
29+
// - Blinds each share with server-specific one-time pads
3030
//
3131
// 2. Aggregation:
32-
// - Aggregators sum client shares in the finite field
33-
// - Multiple aggregation levels can reduce bandwidth hierarchically
32+
// - Aggregators sum client shares in the finite field
33+
// - Multiple aggregation levels can reduce bandwidth hierarchically
3434
//
3535
// 3. Partial Decryption (Server):
36-
// - Each server removes its blinding factors from the aggregate
37-
// - Creates a partial decryption share
36+
// - Each server removes its blinding factors from the aggregate
37+
// - Creates a partial decryption share
3838
//
3939
// 4. Reconstruction (Leader Server):
40-
// - Collects partial decryptions from at least t servers
41-
// - Uses polynomial interpolation to recover original messages
42-
// - Decodes auction IBF to determine next round's winners
40+
// - Collects partial decryptions from at least t servers
41+
// - Uses polynomial interpolation to recover original messages
42+
// - Decodes auction IBF to determine next round's winners
4343
//
4444
// # Cryptographic Primitives (also see crypto package)
4545
//
@@ -71,5 +71,4 @@
7171
// - Privacy: Preserved as long as fewer than t servers collude
7272
// - Anonymity: Unlinkability between rounds via fresh blinding
7373
// - Availability: System operates with any t-of-n servers
74-
//
7574
package protocol

protocol/interfaces.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ type Client interface {
1313
// PrepareMessage creates secret-shared messages for the current round.
1414
// Returns one message per server containing the client's share.
1515
PrepareMessage(ctx context.Context, round int,
16-
previousRoundOutput *ServerRoundData,
16+
previousRoundOutput *RoundBroadcast,
1717
message []byte,
1818
auctionData *blind_auction.AuctionData) ([]*ClientRoundMessage, bool, error)
1919
}
@@ -41,7 +41,7 @@ type Server interface {
4141

4242
// UnblindPartialMessages combines partial decryptions from threshold servers
4343
// to produce the final broadcast containing messages and auction results.
44-
UnblindPartialMessages(msgs []*ServerPartialDecryptionMessage) (*ServerRoundData, error)
44+
UnblindPartialMessages(msgs []*ServerPartialDecryptionMessage) (*RoundBroadcast, error)
4545
}
4646

4747
// ADCNetConfig provides configuration parameters for ADCNet components.
@@ -68,6 +68,10 @@ type ADCNetConfig struct {
6868
RoundsPerWindow uint32
6969
}
7070

71+
func AuctionSlotsForConfig(c *ADCNetConfig) uint32 {
72+
return 2 * blind_auction.IBFVectorSize(c.AuctionSlots)
73+
}
74+
7175
// AuctionResult indicates whether a client won an auction slot.
7276
type AuctionResult struct {
7377
// ShouldSend indicates if the client won a slot.

protocol/messages.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,18 +61,20 @@ func (s *Signed[T]) Recover() (*T, crypto.PublicKey, error) {
6161
return s.Object, s.PublicKey, nil
6262
}
6363

64+
type ServerID int32
65+
6466
// ClientRoundMessage contains a client's secret share for one server.
6567
type ClientRoundMessage struct {
6668
RoundNumber int
67-
ServerID int32
69+
ServerID ServerID
6870
AuctionVector []*big.Int
6971
MessageVector []*big.Int
7072
}
7173

7274
// AggregatedClientMessages contains summed shares from multiple clients.
7375
type AggregatedClientMessages struct {
7476
RoundNumber int
75-
ServerID int32
77+
ServerID ServerID
7678
AuctionVector []*big.Int
7779
MessageVector []*big.Int
7880
UserPKs []crypto.PublicKey
@@ -113,15 +115,15 @@ func (m *AggregatedClientMessages) UnionInplace(o *AggregatedClientMessages) *Ag
113115

114116
// ServerPartialDecryptionMessage contains a server's unblinded share for threshold reconstruction.
115117
type ServerPartialDecryptionMessage struct {
116-
ServerID int32
118+
ServerID ServerID
117119
OriginalAggregate *AggregatedClientMessages
118120
UserPKs []crypto.PublicKey
119121
AuctionVector []*big.Int
120122
MessageVector []*big.Int
121123
}
122124

123-
// ServerRoundData contains the final reconstructed broadcast for a round.
124-
type ServerRoundData struct {
125+
// RoundBroadcast contains the final reconstructed broadcast for a round.
126+
type RoundBroadcast struct {
125127
RoundNumber int
126128
AuctionVector *blind_auction.IBFVector
127129
MessageVector []byte

protocol/protocol_test.go

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@ func TestSecretSharingClient(t *testing.T) {
2525
config := &ADCNetConfig{
2626
AuctionSlots: 10,
2727
MessageSize: 3,
28-
MinServers: 2,
28+
MinServers: 2,
2929
MessageFieldOrder: crypto.MessageFieldOrder,
3030
}
3131

3232
c := &ClientMessager{
3333
Config: config,
34-
SharedSecrets: map[int32]crypto.SharedKey{1: sharedSecret("c1s1"), 2: sharedSecret("c1s2"), 3: sharedSecret("c1s3")},
34+
SharedSecrets: map[ServerID]crypto.SharedKey{1: sharedSecret("c1s1"), 2: sharedSecret("c1s2"), 3: sharedSecret("c1s3")},
3535
}
3636

3737
auctionIBF := blind_auction.NewIBFVector(config.AuctionSlots)
@@ -72,7 +72,7 @@ func TestE2E(t *testing.T) {
7272
AuctionSlots: 10,
7373
MessageSize: 3,
7474
MessageFieldOrder: crypto.MessageFieldOrder,
75-
MinServers: 2,
75+
MinServers: 2,
7676
}
7777

7878
// client1PK, client1SK, _ := crypto.GenerateKeyPair()
@@ -82,7 +82,7 @@ func TestE2E(t *testing.T) {
8282
for s := range servers {
8383
servers[s] = &ServerMessager{
8484
Config: config,
85-
ServerID: int32(s + 1),
85+
ServerID: ServerID(s + 1),
8686
SharedSecrets: make(map[string]crypto.SharedKey),
8787
}
8888
}
@@ -93,7 +93,7 @@ func TestE2E(t *testing.T) {
9393
for c := range clients {
9494
clients[c] = &ClientMessager{
9595
Config: config,
96-
SharedSecrets: make(map[int32]crypto.SharedKey),
96+
SharedSecrets: make(map[ServerID]crypto.SharedKey),
9797
}
9898
var pubkey crypto.PublicKey
9999
pubkey, clientKeys[c], _ = crypto.GenerateKeyPair()
@@ -106,7 +106,7 @@ func TestE2E(t *testing.T) {
106106
}
107107
}
108108

109-
previousRoundOutput := &ServerRoundData{
109+
previousRoundOutput := &RoundBroadcast{
110110
RoundNumber: 1,
111111
AuctionVector: blind_auction.NewIBFVector(config.AuctionSlots),
112112
MessageVector: []byte{},
@@ -145,10 +145,10 @@ func TestE2E(t *testing.T) {
145145
require.Len(t, talkingClients, 2)
146146

147147
agg := &AggregatorMessager{Config: config}
148-
aggregatedMessages, err := agg.AggregateClientMessages(2, clientMsgs, clientPubkeys)
148+
aggregatedMessages, err := agg.AggregateClientMessages(2, nil, clientMsgs, clientPubkeys)
149149
require.NoError(t, err)
150150
require.Len(t, aggregatedMessages, 3) // one message per server
151-
aggregatedMessagesPerServer := make(map[int32]*AggregatedClientMessages, 3)
151+
aggregatedMessagesPerServer := make(map[ServerID]*AggregatedClientMessages, 3)
152152
for _, msg := range aggregatedMessages {
153153
aggregatedMessagesPerServer[msg.ServerID] = msg
154154
}
@@ -221,7 +221,7 @@ func BenchmarkUnblindAggregate(b *testing.B) {
221221
AuctionSlots: 10,
222222
MessageSize: uint32(msgVectorSlots),
223223
MessageFieldOrder: fieldOrder,
224-
MinServers: 2,
224+
MinServers: 2,
225225
},
226226
ServerID: 1,
227227
SharedSecrets: sharedSecrets,
@@ -272,22 +272,22 @@ func BenchmarkUnblindMessages(b *testing.B) {
272272
userPKs[i] = pubkey
273273
}
274274

275-
for _, msgVectorSlots := range msgSizeBenches {
276-
for _, nServers := range nServerBenches {
277-
for _, nClients := range nClientBenches {
275+
for _, msgVectorSlots := range msgSizeBenches {
276+
for _, nServers := range nServerBenches {
277+
for _, nClients := range nClientBenches {
278278
b.Run(fmt.Sprintf("Unblind partial messages servers-%d-clients-%d-msg-%d-field-%d", nServers, nClients, msgVectorSlots, fieldOrder.BitLen()), func(b *testing.B) {
279279

280280
config := &ADCNetConfig{
281281
AuctionSlots: 10,
282282
MessageSize: uint32(msgVectorSlots),
283283
MessageFieldOrder: fieldOrder,
284-
MinServers: uint32(nServers),
284+
MinServers: uint32(nServers),
285285
}
286286

287287
pdm := make([]*ServerPartialDecryptionMessage, nServers)
288288
for i := range pdm {
289289
pdm[i] = &ServerPartialDecryptionMessage{
290-
ServerID: int32(i + 1),
290+
ServerID: ServerID(i + 1),
291291
OriginalAggregate: &AggregatedClientMessages{RoundNumber: 1},
292292
UserPKs: userPKs[:nClients],
293293
AuctionVector: []*big.Int{},

0 commit comments

Comments
 (0)