@@ -56,6 +56,7 @@ package ot
5656import (
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.
227259func (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