Skip to content

Commit 4c1a8ba

Browse files
committed
Added batched correlated bit-OT API.
1 parent 81d03f8 commit 4c1a8ba

1 file changed

Lines changed: 88 additions & 16 deletions

File tree

‎ot/iknp.go‎

Lines changed: 88 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ package ot
5656
import (
5757
"crypto/aes"
5858
"crypto/cipher"
59+
"encoding/binary"
5960
"fmt"
6061
"io"
6162
)
@@ -224,16 +225,44 @@ func (s *IKNPSender) send(n int) ([]Label, error) {
224225
return result, nil
225226
}
226227

228+
// SendBits performs n batched correlated bit-OTs (COT) as the IKNP sender.
229+
//
230+
// For each i ∈ {0, …, n-1}, this function outputs a random bit s_i
231+
// into result such that the receiver obtains:
232+
//
233+
// r_i = s_i ⊕ (b_i · Δ)
234+
//
235+
// where:
236+
//
237+
// - b_i is the receiver's choice bit,
238+
// - Δ is the fixed IKNP correlation value defined at sender setup,
239+
// - s_i and r_i are bits.
240+
//
241+
// Only one bit of the 128-bit IKNP label (bit 0) is used, so this
242+
// implements *bit-level correlated OT* on top of standard IKNP.
243+
//
244+
// The function writes exactly n bits into result using packed
245+
// little-endian bit representation:
246+
//
247+
// - Bit i is stored in result[i/64] at position (i % 64),
248+
// - Bit 0 is the least-significant bit of result[0].
249+
//
250+
// The caller must provide a result slice with capacity at least
251+
// (n+63)/64 words. Existing contents are overwritten.
252+
//
253+
// Security:
254+
// - Correlation security is 128-bit (IKNP parameter K).
255+
// - All n OTs share the same fixed 128-bit Δ.
256+
// - n may be arbitrarily large; security does not depend on n.
257+
//
258+
// Returns an error if communication fails or buffers are invalid.
227259
func (s *IKNPSender) SendBits(n int, result []uint64) error {
228-
229260
if (n+63)/64 > len(result) {
230261
return fmt.Errorf("result buffer len=%v too short for n=%v",
231262
len(result), n)
232263
}
233264

234-
ofs := 0
235-
236-
for ofs < n {
265+
for ofs := 0; ofs < n; {
237266
chunk, err := s.io.ReceiveData()
238267
if err != nil {
239268
return err
@@ -264,7 +293,6 @@ func (s *IKNPSender) SendBits(n int, result []uint64) error {
264293
}
265294

266295
for row := 0; row < maxRows; row++ {
267-
268296
byteIndex := row / 8
269297
bitIndex := row % 8
270298

@@ -482,21 +510,57 @@ func (r *IKNPReceiver) receive(b []bool, result []Label) error {
482510
return nil
483511
}
484512

485-
func (r *IKNPReceiver) ReceiveBits(b []bool, result []uint64) error {
486-
487-
n := len(b)
513+
// ReceiveBits performs n batched correlated bit-OTs (COT) as the IKNP
514+
// receiver.
515+
//
516+
// For each i ∈ {0, …, n-1}, the receiver provides a choice bit b_i
517+
// and obtains a correlated output bit r_i such that:
518+
//
519+
// r_i = s_i ⊕ (b_i · Δ)
520+
//
521+
// where:
522+
//
523+
// - s_i is the sender's random output bit,
524+
// - Δ is the fixed 128-bit IKNP correlation value defined at sender setup,
525+
// - r_i is written into result.
526+
//
527+
// Only one bit of the 128-bit IKNP label (bit 0) is used, so this
528+
// implements *bit-level correlated OT* on top of standard IKNP.
529+
//
530+
// Parameters:
531+
//
532+
// choices Packed bit vector containing n choice bits.
533+
// Bit i is read from choices[i/64] at position (i % 64),
534+
// where bit 0 is the least-significant bit of choices[0].
535+
//
536+
// result Packed bit vector receiving n output bits using the
537+
// same little-endian layout.
538+
//
539+
// n Number of bit-OT instances to execute.
540+
//
541+
// The caller must ensure:
542+
//
543+
// - len(choices) ≥ (n+63)/64
544+
// - len(result) ≥ (n+63)/64
545+
//
546+
// Existing contents of result are overwritten.
547+
//
548+
// Security:
549+
// - Correlation security is 128-bit (IKNP parameter K).
550+
// - All n OTs share the same fixed 128-bit Δ.
551+
// - Security does not depend on n.
552+
//
553+
// Returns an error if communication fails or buffers are invalid.
554+
func (r *IKNPReceiver) ReceiveBits(choices, result []uint64, n int) error {
555+
if (n+63)/64 > len(choices) {
556+
return fmt.Errorf("choices buffer len=%v too short for n=%v",
557+
len(result), n)
558+
}
488559
if (n+63)/64 > len(result) {
489560
return fmt.Errorf("result buffer len=%v too short for n=%v",
490561
len(result), n)
491562
}
492563

493-
bbuf := make([]byte, (n+7)/8)
494-
for i, f := range b {
495-
if f {
496-
bbuf[i/8] |= 1 << (i % 8)
497-
}
498-
}
499-
500564
var chunk, tmp [chunkSize]byte
501565

502566
for ofs := 0; ofs < n; {
@@ -510,14 +574,22 @@ func (r *IKNPReceiver) ReceiveBits(b []bool, result []uint64) error {
510574

511575
var ucol [chunkSize]byte
512576

577+
wordOffset := ofs / 64
578+
words := byteRows / 8
579+
513580
// Build u-matrix columns (identical to receive())
514581
for i := 0; i < K; i++ {
515582

516583
prg(r.g0[i], chunk[i*byteRows:(i+1)*byteRows])
517584
prg(r.g1[i], tmp[:byteRows])
518585

519586
xor(tmp[:byteRows], chunk[i*byteRows:])
520-
xor(tmp[:byteRows], bbuf[ofs/8:])
587+
588+
for w := 0; w < words; w++ {
589+
tmpWord := binary.LittleEndian.Uint64(tmp[w*8:])
590+
tmpWord ^= choices[wordOffset+w]
591+
binary.LittleEndian.PutUint64(tmp[w*8:], tmpWord)
592+
}
521593

522594
copy(ucol[i*byteRows:], tmp[:byteRows])
523595
}

0 commit comments

Comments
 (0)