charm-crypto-framework 0.61.1__cp313-cp313-macosx_10_13_universal2.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (323) hide show
  1. charm/__init__.py +5 -0
  2. charm/adapters/__init__.py +0 -0
  3. charm/adapters/abenc_adapt_hybrid.py +90 -0
  4. charm/adapters/dabenc_adapt_hybrid.py +145 -0
  5. charm/adapters/ibenc_adapt_hybrid.py +72 -0
  6. charm/adapters/ibenc_adapt_identityhash.py +80 -0
  7. charm/adapters/kpabenc_adapt_hybrid.py +91 -0
  8. charm/adapters/pkenc_adapt_bchk05.py +121 -0
  9. charm/adapters/pkenc_adapt_chk04.py +91 -0
  10. charm/adapters/pkenc_adapt_hybrid.py +98 -0
  11. charm/adapters/pksig_adapt_naor01.py +89 -0
  12. charm/config.py +7 -0
  13. charm/core/__init__.py +0 -0
  14. charm/core/benchmark/benchmark_util.c +353 -0
  15. charm/core/benchmark/benchmark_util.h +61 -0
  16. charm/core/benchmark/benchmarkmodule.c +476 -0
  17. charm/core/benchmark/benchmarkmodule.h +162 -0
  18. charm/core/benchmark.cpython-313-darwin.so +0 -0
  19. charm/core/crypto/AES/AES.c +1464 -0
  20. charm/core/crypto/AES.cpython-313-darwin.so +0 -0
  21. charm/core/crypto/DES/DES.c +113 -0
  22. charm/core/crypto/DES.cpython-313-darwin.so +0 -0
  23. charm/core/crypto/DES3/DES3.c +26 -0
  24. charm/core/crypto/DES3.cpython-313-darwin.so +0 -0
  25. charm/core/crypto/__init__.py +0 -0
  26. charm/core/crypto/cryptobase/XOR.c +80 -0
  27. charm/core/crypto/cryptobase/_counter.c +496 -0
  28. charm/core/crypto/cryptobase/_counter.h +54 -0
  29. charm/core/crypto/cryptobase/block_template.c +900 -0
  30. charm/core/crypto/cryptobase/block_template.h +69 -0
  31. charm/core/crypto/cryptobase/cryptobasemodule.c +220 -0
  32. charm/core/crypto/cryptobase/libtom/tomcrypt.h +90 -0
  33. charm/core/crypto/cryptobase/libtom/tomcrypt_argchk.h +44 -0
  34. charm/core/crypto/cryptobase/libtom/tomcrypt_cfg.h +186 -0
  35. charm/core/crypto/cryptobase/libtom/tomcrypt_cipher.h +941 -0
  36. charm/core/crypto/cryptobase/libtom/tomcrypt_custom.h +556 -0
  37. charm/core/crypto/cryptobase/libtom/tomcrypt_des.c +1912 -0
  38. charm/core/crypto/cryptobase/libtom/tomcrypt_hash.h +407 -0
  39. charm/core/crypto/cryptobase/libtom/tomcrypt_mac.h +496 -0
  40. charm/core/crypto/cryptobase/libtom/tomcrypt_macros.h +435 -0
  41. charm/core/crypto/cryptobase/libtom/tomcrypt_math.h +534 -0
  42. charm/core/crypto/cryptobase/libtom/tomcrypt_misc.h +103 -0
  43. charm/core/crypto/cryptobase/libtom/tomcrypt_pk.h +653 -0
  44. charm/core/crypto/cryptobase/libtom/tomcrypt_pkcs.h +90 -0
  45. charm/core/crypto/cryptobase/libtom/tomcrypt_prng.h +199 -0
  46. charm/core/crypto/cryptobase/stream_template.c +271 -0
  47. charm/core/crypto/cryptobase/strxor.c +229 -0
  48. charm/core/crypto/cryptobase.cpython-313-darwin.so +0 -0
  49. charm/core/engine/__init__.py +5 -0
  50. charm/core/engine/protocol.py +293 -0
  51. charm/core/engine/util.py +174 -0
  52. charm/core/math/__init__.py +0 -0
  53. charm/core/math/elliptic_curve/ecmodule.c +1986 -0
  54. charm/core/math/elliptic_curve/ecmodule.h +230 -0
  55. charm/core/math/elliptic_curve.cpython-313-darwin.so +0 -0
  56. charm/core/math/elliptic_curve.pyi +63 -0
  57. charm/core/math/integer/integermodule.c +2539 -0
  58. charm/core/math/integer/integermodule.h +145 -0
  59. charm/core/math/integer.cpython-313-darwin.so +0 -0
  60. charm/core/math/integer.pyi +76 -0
  61. charm/core/math/pairing/miracl/miracl_config.h +37 -0
  62. charm/core/math/pairing/miracl/miracl_interface.h +118 -0
  63. charm/core/math/pairing/miracl/miracl_interface2.h +126 -0
  64. charm/core/math/pairing/miracl/pairingmodule2.c +2094 -0
  65. charm/core/math/pairing/miracl/pairingmodule2.h +307 -0
  66. charm/core/math/pairing/pairingmodule.c +2230 -0
  67. charm/core/math/pairing/pairingmodule.h +241 -0
  68. charm/core/math/pairing/relic/pairingmodule3.c +1853 -0
  69. charm/core/math/pairing/relic/pairingmodule3.h +233 -0
  70. charm/core/math/pairing/relic/relic_interface.c +1337 -0
  71. charm/core/math/pairing/relic/relic_interface.h +217 -0
  72. charm/core/math/pairing/relic/test_relic.c +171 -0
  73. charm/core/math/pairing.cpython-313-darwin.so +0 -0
  74. charm/core/math/pairing.pyi +69 -0
  75. charm/core/utilities/base64.c +248 -0
  76. charm/core/utilities/base64.h +15 -0
  77. charm/schemes/__init__.py +0 -0
  78. charm/schemes/abenc/__init__.py +0 -0
  79. charm/schemes/abenc/abenc_accountability_jyjxgd20.py +647 -0
  80. charm/schemes/abenc/abenc_bsw07.py +146 -0
  81. charm/schemes/abenc/abenc_ca_cpabe_ar17.py +684 -0
  82. charm/schemes/abenc/abenc_dacmacs_yj14.py +298 -0
  83. charm/schemes/abenc/abenc_lsw08.py +159 -0
  84. charm/schemes/abenc/abenc_maabe_rw15.py +236 -0
  85. charm/schemes/abenc/abenc_maabe_yj14.py +297 -0
  86. charm/schemes/abenc/abenc_tbpre_lww14.py +309 -0
  87. charm/schemes/abenc/abenc_unmcpabe_yahk14.py +223 -0
  88. charm/schemes/abenc/abenc_waters09.py +144 -0
  89. charm/schemes/abenc/abenc_yct14.py +208 -0
  90. charm/schemes/abenc/abenc_yllc15.py +178 -0
  91. charm/schemes/abenc/ac17.py +248 -0
  92. charm/schemes/abenc/bsw07.py +141 -0
  93. charm/schemes/abenc/cgw15.py +277 -0
  94. charm/schemes/abenc/dabe_aw11.py +204 -0
  95. charm/schemes/abenc/dfa_fe12.py +144 -0
  96. charm/schemes/abenc/pk_hve08.py +179 -0
  97. charm/schemes/abenc/waters11.py +143 -0
  98. charm/schemes/aggrsign_MuSig.py +150 -0
  99. charm/schemes/aggrsign_bls.py +267 -0
  100. charm/schemes/blindsig_ps16.py +654 -0
  101. charm/schemes/chamhash_adm05.py +113 -0
  102. charm/schemes/chamhash_rsa_hw09.py +100 -0
  103. charm/schemes/commit/__init__.py +0 -0
  104. charm/schemes/commit/commit_gs08.py +77 -0
  105. charm/schemes/commit/commit_pedersen92.py +53 -0
  106. charm/schemes/encap_bchk05.py +62 -0
  107. charm/schemes/grpsig/__init__.py +0 -0
  108. charm/schemes/grpsig/groupsig_bgls04.py +114 -0
  109. charm/schemes/grpsig/groupsig_bgls04_var.py +115 -0
  110. charm/schemes/hibenc/__init__.py +0 -0
  111. charm/schemes/hibenc/hibenc_bb04.py +105 -0
  112. charm/schemes/hibenc/hibenc_lew11.py +193 -0
  113. charm/schemes/ibenc/__init__.py +0 -0
  114. charm/schemes/ibenc/clpkc_rp03.py +119 -0
  115. charm/schemes/ibenc/ibenc_CW13_z.py +168 -0
  116. charm/schemes/ibenc/ibenc_bb03.py +94 -0
  117. charm/schemes/ibenc/ibenc_bf01.py +121 -0
  118. charm/schemes/ibenc/ibenc_ckrs09.py +120 -0
  119. charm/schemes/ibenc/ibenc_cllww12_z.py +172 -0
  120. charm/schemes/ibenc/ibenc_lsw08.py +120 -0
  121. charm/schemes/ibenc/ibenc_sw05.py +238 -0
  122. charm/schemes/ibenc/ibenc_waters05.py +144 -0
  123. charm/schemes/ibenc/ibenc_waters05_z.py +164 -0
  124. charm/schemes/ibenc/ibenc_waters09.py +107 -0
  125. charm/schemes/ibenc/ibenc_waters09_z.py +147 -0
  126. charm/schemes/joye_scheme.py +106 -0
  127. charm/schemes/lem_scheme.py +207 -0
  128. charm/schemes/pk_fre_ccv11.py +107 -0
  129. charm/schemes/pk_vrf.py +127 -0
  130. charm/schemes/pkenc/__init__.py +0 -0
  131. charm/schemes/pkenc/pkenc_cs98.py +108 -0
  132. charm/schemes/pkenc/pkenc_elgamal85.py +122 -0
  133. charm/schemes/pkenc/pkenc_gm82.py +98 -0
  134. charm/schemes/pkenc/pkenc_paillier99.py +118 -0
  135. charm/schemes/pkenc/pkenc_rabin.py +254 -0
  136. charm/schemes/pkenc/pkenc_rsa.py +186 -0
  137. charm/schemes/pksig/__init__.py +0 -0
  138. charm/schemes/pksig/pksig_CW13_z.py +135 -0
  139. charm/schemes/pksig/pksig_bls04.py +87 -0
  140. charm/schemes/pksig/pksig_boyen.py +156 -0
  141. charm/schemes/pksig/pksig_chch.py +97 -0
  142. charm/schemes/pksig/pksig_chp.py +70 -0
  143. charm/schemes/pksig/pksig_cl03.py +150 -0
  144. charm/schemes/pksig/pksig_cl04.py +87 -0
  145. charm/schemes/pksig/pksig_cllww12_z.py +142 -0
  146. charm/schemes/pksig/pksig_cyh.py +132 -0
  147. charm/schemes/pksig/pksig_dsa.py +76 -0
  148. charm/schemes/pksig/pksig_ecdsa.py +71 -0
  149. charm/schemes/pksig/pksig_hess.py +104 -0
  150. charm/schemes/pksig/pksig_hw.py +110 -0
  151. charm/schemes/pksig/pksig_lamport.py +63 -0
  152. charm/schemes/pksig/pksig_ps01.py +135 -0
  153. charm/schemes/pksig/pksig_ps02.py +124 -0
  154. charm/schemes/pksig/pksig_ps03.py +119 -0
  155. charm/schemes/pksig/pksig_rsa_hw09.py +206 -0
  156. charm/schemes/pksig/pksig_schnorr91.py +77 -0
  157. charm/schemes/pksig/pksig_waters.py +115 -0
  158. charm/schemes/pksig/pksig_waters05.py +121 -0
  159. charm/schemes/pksig/pksig_waters09.py +121 -0
  160. charm/schemes/pre_mg07.py +150 -0
  161. charm/schemes/prenc/pre_afgh06.py +126 -0
  162. charm/schemes/prenc/pre_bbs98.py +123 -0
  163. charm/schemes/prenc/pre_nal16.py +216 -0
  164. charm/schemes/protocol_a01.py +272 -0
  165. charm/schemes/protocol_ao00.py +215 -0
  166. charm/schemes/protocol_cns07.py +274 -0
  167. charm/schemes/protocol_schnorr91.py +125 -0
  168. charm/schemes/sigma1.py +64 -0
  169. charm/schemes/sigma2.py +129 -0
  170. charm/schemes/sigma3.py +126 -0
  171. charm/schemes/threshold/__init__.py +59 -0
  172. charm/schemes/threshold/dkls23_dkg.py +556 -0
  173. charm/schemes/threshold/dkls23_presign.py +1089 -0
  174. charm/schemes/threshold/dkls23_sign.py +761 -0
  175. charm/schemes/threshold/xrpl_wallet.py +967 -0
  176. charm/test/__init__.py +0 -0
  177. charm/test/adapters/__init__.py +0 -0
  178. charm/test/adapters/abenc_adapt_hybrid_test.py +29 -0
  179. charm/test/adapters/dabenc_adapt_hybrid_test.py +56 -0
  180. charm/test/adapters/ibenc_adapt_hybrid_test.py +36 -0
  181. charm/test/adapters/ibenc_adapt_identityhash_test.py +32 -0
  182. charm/test/adapters/kpabenc_adapt_hybrid_test.py +30 -0
  183. charm/test/benchmark/abenc_yllc15_bench.py +92 -0
  184. charm/test/benchmark/benchmark_test.py +148 -0
  185. charm/test/benchmark_threshold.py +260 -0
  186. charm/test/conftest.py +38 -0
  187. charm/test/fuzz/__init__.py +1 -0
  188. charm/test/fuzz/conftest.py +5 -0
  189. charm/test/fuzz/fuzz_policy_parser.py +76 -0
  190. charm/test/fuzz/fuzz_serialization.py +83 -0
  191. charm/test/schemes/__init__.py +0 -0
  192. charm/test/schemes/abenc/__init__.py +0 -0
  193. charm/test/schemes/abenc/abenc_bsw07_test.py +39 -0
  194. charm/test/schemes/abenc/abenc_dacmacs_yj14_test.py +16 -0
  195. charm/test/schemes/abenc/abenc_lsw08_test.py +33 -0
  196. charm/test/schemes/abenc/abenc_maabe_yj14_test.py +16 -0
  197. charm/test/schemes/abenc/abenc_tbpre_lww14_test.py +16 -0
  198. charm/test/schemes/abenc/abenc_waters09_test.py +38 -0
  199. charm/test/schemes/abenc/abenc_yllc15_test.py +74 -0
  200. charm/test/schemes/chamhash_adm05_test.py +31 -0
  201. charm/test/schemes/chamhash_rsa_hw09_test.py +29 -0
  202. charm/test/schemes/commit/__init__.py +0 -0
  203. charm/test/schemes/commit/commit_gs08_test.py +24 -0
  204. charm/test/schemes/commit/commit_pedersen92_test.py +26 -0
  205. charm/test/schemes/dabe_aw11_test.py +45 -0
  206. charm/test/schemes/encap_bchk05_test.py +21 -0
  207. charm/test/schemes/grpsig/__init__.py +0 -0
  208. charm/test/schemes/grpsig/groupsig_bgls04_test.py +35 -0
  209. charm/test/schemes/grpsig/groupsig_bgls04_var_test.py +39 -0
  210. charm/test/schemes/hibenc/__init__.py +0 -0
  211. charm/test/schemes/hibenc/hibenc_bb04_test.py +28 -0
  212. charm/test/schemes/ibenc/__init__.py +0 -0
  213. charm/test/schemes/ibenc/ibenc_bb03_test.py +26 -0
  214. charm/test/schemes/ibenc/ibenc_bf01_test.py +24 -0
  215. charm/test/schemes/ibenc/ibenc_ckrs09_test.py +25 -0
  216. charm/test/schemes/ibenc/ibenc_lsw08_test.py +31 -0
  217. charm/test/schemes/ibenc/ibenc_sw05_test.py +32 -0
  218. charm/test/schemes/ibenc/ibenc_waters05_test.py +31 -0
  219. charm/test/schemes/ibenc/ibenc_waters09_test.py +27 -0
  220. charm/test/schemes/pk_vrf_test.py +29 -0
  221. charm/test/schemes/pkenc/__init__.py +0 -0
  222. charm/test/schemes/pkenc_test.py +255 -0
  223. charm/test/schemes/pksig/__init__.py +0 -0
  224. charm/test/schemes/pksig_test.py +376 -0
  225. charm/test/schemes/rsa_alg_test.py +340 -0
  226. charm/test/schemes/threshold_test.py +1792 -0
  227. charm/test/serialize/__init__.py +0 -0
  228. charm/test/serialize/serialize_test.py +40 -0
  229. charm/test/toolbox/__init__.py +0 -0
  230. charm/test/toolbox/conversion_test.py +30 -0
  231. charm/test/toolbox/ecgroup_test.py +53 -0
  232. charm/test/toolbox/integer_arithmetic_test.py +441 -0
  233. charm/test/toolbox/paddingschemes_test.py +238 -0
  234. charm/test/toolbox/policy_parser_stress_test.py +969 -0
  235. charm/test/toolbox/secretshare_test.py +28 -0
  236. charm/test/toolbox/symcrypto_test.py +108 -0
  237. charm/test/toolbox/test_policy_expression.py +16 -0
  238. charm/test/vectors/__init__.py +1 -0
  239. charm/test/vectors/test_bls_vectors.py +289 -0
  240. charm/test/vectors/test_pedersen_vectors.py +315 -0
  241. charm/test/vectors/test_schnorr_vectors.py +368 -0
  242. charm/test/zkp_compiler/__init__.py +9 -0
  243. charm/test/zkp_compiler/benchmark_zkp.py +258 -0
  244. charm/test/zkp_compiler/test_and_proof.py +240 -0
  245. charm/test/zkp_compiler/test_batch_verify.py +248 -0
  246. charm/test/zkp_compiler/test_dleq_proof.py +264 -0
  247. charm/test/zkp_compiler/test_or_proof.py +231 -0
  248. charm/test/zkp_compiler/test_proof_serialization.py +121 -0
  249. charm/test/zkp_compiler/test_range_proof.py +241 -0
  250. charm/test/zkp_compiler/test_representation_proof.py +325 -0
  251. charm/test/zkp_compiler/test_schnorr_proof.py +221 -0
  252. charm/test/zkp_compiler/test_thread_safety.py +169 -0
  253. charm/test/zkp_compiler/test_zkp_parser.py +139 -0
  254. charm/toolbox/ABEnc.py +26 -0
  255. charm/toolbox/ABEncMultiAuth.py +66 -0
  256. charm/toolbox/ABEnumeric.py +800 -0
  257. charm/toolbox/Commit.py +24 -0
  258. charm/toolbox/DFA.py +89 -0
  259. charm/toolbox/FSA.py +1254 -0
  260. charm/toolbox/Hash.py +39 -0
  261. charm/toolbox/IBEnc.py +62 -0
  262. charm/toolbox/IBSig.py +64 -0
  263. charm/toolbox/PKEnc.py +66 -0
  264. charm/toolbox/PKSig.py +56 -0
  265. charm/toolbox/PREnc.py +32 -0
  266. charm/toolbox/ZKProof.py +289 -0
  267. charm/toolbox/__init__.py +0 -0
  268. charm/toolbox/bitstring.py +49 -0
  269. charm/toolbox/broadcast.py +220 -0
  270. charm/toolbox/conversion.py +100 -0
  271. charm/toolbox/eccurve.py +149 -0
  272. charm/toolbox/ecgroup.py +143 -0
  273. charm/toolbox/enum.py +60 -0
  274. charm/toolbox/hash_module.py +91 -0
  275. charm/toolbox/integergroup.py +323 -0
  276. charm/toolbox/iterate.py +22 -0
  277. charm/toolbox/matrixops.py +76 -0
  278. charm/toolbox/mpc_utils.py +296 -0
  279. charm/toolbox/msp.py +175 -0
  280. charm/toolbox/mta.py +985 -0
  281. charm/toolbox/node.py +120 -0
  282. charm/toolbox/ot/__init__.py +22 -0
  283. charm/toolbox/ot/base_ot.py +374 -0
  284. charm/toolbox/ot/dpf.py +642 -0
  285. charm/toolbox/ot/mpfss.py +228 -0
  286. charm/toolbox/ot/ot_extension.py +589 -0
  287. charm/toolbox/ot/silent_ot.py +378 -0
  288. charm/toolbox/paddingschemes.py +423 -0
  289. charm/toolbox/paddingschemes_test.py +238 -0
  290. charm/toolbox/pairingcurves.py +85 -0
  291. charm/toolbox/pairinggroup.py +186 -0
  292. charm/toolbox/policy_expression_spec.py +70 -0
  293. charm/toolbox/policytree.py +189 -0
  294. charm/toolbox/reCompiler.py +346 -0
  295. charm/toolbox/redundancyschemes.py +65 -0
  296. charm/toolbox/schemebase.py +188 -0
  297. charm/toolbox/secretshare.py +104 -0
  298. charm/toolbox/secretutil.py +174 -0
  299. charm/toolbox/securerandom.py +73 -0
  300. charm/toolbox/sigmaprotocol.py +46 -0
  301. charm/toolbox/specialprimes.py +45 -0
  302. charm/toolbox/symcrypto.py +279 -0
  303. charm/toolbox/threshold_sharing.py +553 -0
  304. charm/toolbox/xmlserialize.py +94 -0
  305. charm/toolbox/zknode.py +105 -0
  306. charm/zkp_compiler/__init__.py +89 -0
  307. charm/zkp_compiler/and_proof.py +460 -0
  308. charm/zkp_compiler/batch_verify.py +324 -0
  309. charm/zkp_compiler/dleq_proof.py +423 -0
  310. charm/zkp_compiler/or_proof.py +305 -0
  311. charm/zkp_compiler/range_proof.py +417 -0
  312. charm/zkp_compiler/representation_proof.py +466 -0
  313. charm/zkp_compiler/schnorr_proof.py +273 -0
  314. charm/zkp_compiler/thread_safe.py +150 -0
  315. charm/zkp_compiler/zk_demo.py +489 -0
  316. charm/zkp_compiler/zkp_factory.py +330 -0
  317. charm/zkp_compiler/zkp_generator.py +370 -0
  318. charm/zkp_compiler/zkparser.py +269 -0
  319. charm_crypto_framework-0.61.1.dist-info/METADATA +337 -0
  320. charm_crypto_framework-0.61.1.dist-info/RECORD +323 -0
  321. charm_crypto_framework-0.61.1.dist-info/WHEEL +5 -0
  322. charm_crypto_framework-0.61.1.dist-info/licenses/LICENSE.txt +165 -0
  323. charm_crypto_framework-0.61.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,378 @@
1
+ '''
2
+ Silent OT Extension based on Pseudorandom Correlation Generators
3
+
4
+ | From: "Efficient Pseudorandom Correlation Generators: Silent OT Extension and More"
5
+ | By: Elette Boyle, Geoffroy Couteau, Niv Gilboa, Yuval Ishai, Lisa Kohl, Peter Scholl
6
+ | Published: CRYPTO 2019
7
+ | URL: https://eprint.iacr.org/2019/448
8
+
9
+ * type: oblivious transfer extension
10
+ * setting: pseudorandom correlation generator
11
+ * assumption: LPN, PRG security
12
+
13
+ :Authors: Elton de Souza
14
+ :Date: 01/2026
15
+ '''
16
+
17
+ import hashlib
18
+ import secrets
19
+ import logging
20
+ import math
21
+ from typing import Tuple, List
22
+
23
+ from charm.toolbox.ot.mpfss import MPFSS
24
+
25
+ logger = logging.getLogger(__name__)
26
+
27
+ # Seed serialization version for forward compatibility
28
+ SEED_VERSION = 1
29
+
30
+ # Modulus for arithmetic operations (2^64 for efficiency)
31
+ MODULUS = 1 << 64
32
+
33
+
34
+ class SilentOT:
35
+ """
36
+ Silent OT Extension using Pseudorandom Correlation Generators.
37
+
38
+ Generates n pseudo-random OT instances using sublinear communication.
39
+ Uses MPFSS as a building block for compressing sparse vectors.
40
+
41
+ The construction follows Figure 4 from the paper:
42
+ 1. GsVOLE generates VOLE correlations from MPFSS
43
+ 2. GOT converts VOLE to random OT using correlation-robust hash
44
+
45
+ >>> sot = SilentOT(security_param=128, output_size=64, sparsity=8)
46
+ >>> seed_sender, seed_receiver = sot.gen()
47
+ >>> len(seed_sender) > 0 and len(seed_receiver) > 0
48
+ True
49
+ >>> choice_bits, sender_msgs = sot.expand_sender(seed_sender)
50
+ >>> receiver_msgs = sot.expand_receiver(seed_receiver)
51
+ >>> len(choice_bits) == 64 and len(sender_msgs) == 64
52
+ True
53
+ >>> len(receiver_msgs) == 64
54
+ True
55
+ >>> # Verify OT correlation: sender_msg[i] == receiver_msg[i][choice_bits[i]]
56
+ >>> all(sender_msgs[i] == receiver_msgs[i][choice_bits[i]] for i in range(64))
57
+ True
58
+ """
59
+
60
+ def __init__(self,
61
+ security_param: int = 128,
62
+ output_size: int = 1024,
63
+ sparsity: int = None):
64
+ """
65
+ Initialize Silent OT.
66
+
67
+ Parameters
68
+ ----------
69
+ security_param : int
70
+ Security parameter λ (128 or 256)
71
+ output_size : int
72
+ Number n of OT instances to generate
73
+ sparsity : int
74
+ Parameter t for sparse vector (default: sqrt(n))
75
+ """
76
+ if security_param not in (128, 256):
77
+ raise ValueError("security_param must be 128 or 256")
78
+ if output_size < 1:
79
+ raise ValueError("output_size must be at least 1")
80
+
81
+ self.security_param = security_param
82
+ self.n = output_size
83
+ # Sparsity parameter t, default to sqrt(n)
84
+ self.t = sparsity if sparsity is not None else max(1, int(math.sqrt(output_size)))
85
+
86
+ # Domain size n' for MPFSS (must be power of 2 >= n)
87
+ self.domain_bits = max(1, (self.n - 1).bit_length())
88
+ self.n_prime = 1 << self.domain_bits
89
+
90
+ # Validate sparsity bounds
91
+ if self.t < 1:
92
+ raise ValueError(f"sparsity must be at least 1, got {self.t}")
93
+ if self.t > self.n_prime:
94
+ raise ValueError(
95
+ f"sparsity ({self.t}) cannot exceed domain size n' ({self.n_prime})"
96
+ )
97
+
98
+ # Initialize MPFSS for function secret sharing
99
+ self._mpfss = MPFSS(security_param=security_param, domain_bits=self.domain_bits)
100
+
101
+ logger.debug("SilentOT initialized: n=%d, t=%d, n'=%d", self.n, self.t, self.n_prime)
102
+
103
+ def _prg(self, seed: bytes, output_length: int) -> bytes:
104
+ """PRG using SHA-256 in counter mode."""
105
+ output = b''
106
+ counter = 0
107
+ while len(output) < output_length:
108
+ h = hashlib.sha256()
109
+ h.update(seed)
110
+ h.update(counter.to_bytes(4, 'big'))
111
+ output += h.digest()
112
+ counter += 1
113
+ return output[:output_length]
114
+
115
+ def correlation_robust_hash(self, index: int, value: int) -> bytes:
116
+ """
117
+ Correlation-robust hash H(i, v).
118
+
119
+ Uses SHA-256 as the underlying hash function.
120
+
121
+ Parameters
122
+ ----------
123
+ index : int
124
+ OT index
125
+ value : int
126
+ Value to hash (reduced mod 2^64)
127
+
128
+ Returns
129
+ -------
130
+ bytes
131
+ 32-byte hash output
132
+ """
133
+ # Reduce value to 64-bit range for consistent hashing
134
+ value_reduced = value % MODULUS
135
+ h = hashlib.sha256()
136
+ h.update(index.to_bytes(8, 'big'))
137
+ h.update(value_reduced.to_bytes(8, 'big'))
138
+ return h.digest()
139
+
140
+ def gen(self) -> Tuple[bytes, bytes]:
141
+ """
142
+ Generate PCG seeds for sender (party 0) and receiver (party 1).
143
+
144
+ Implements GsVOLE.Gen from Figure 3 adapted for binary VOLE:
145
+ 1. Pick random size-t subset S of [n']
146
+ 2. Pick x ∈ F_q as receiver's global delta
147
+ 3. Set y[i] = 1 for all i (to get binary u values after compression)
148
+ 4. Compute (K_fss_0, K_fss_1) ← MPFSS.Gen(1^λ, f_{S, x·y})
149
+ 5. k0 ← (n, n', K_fss_0, S, y, matrix_seed)
150
+ 6. k1 ← (n, n', K_fss_1, x, matrix_seed)
151
+
152
+ The VOLE correlation is: w = u * x + v
153
+ Where u ∈ {0,1}^n are the choice bits (sparse after LPN compression).
154
+
155
+ Returns
156
+ -------
157
+ Tuple[bytes, bytes]
158
+ (seed_sender, seed_receiver) - Seeds for both parties
159
+ """
160
+ # 1. Pick random size-t subset S of [n'] using cryptographically secure sampling
161
+ secure_random = secrets.SystemRandom()
162
+ S = sorted(secure_random.sample(range(self.n_prime), self.t))
163
+
164
+ # 2. Pick random x ∈ F_q as the correlation value (receiver's delta)
165
+ x = secrets.randbelow(MODULUS)
166
+ if x == 0:
167
+ x = 1 # Ensure non-zero for proper correlation
168
+
169
+ # 3. For binary VOLE (to get u ∈ {0,1}), set y[i] = 1
170
+ # This means sparse vector has 1s at positions S, 0 elsewhere
171
+ # After multiplication with random H matrix, we get random values
172
+ # but we'll use a different approach: directly encode choice bits
173
+ y = [1 for _ in range(self.t)]
174
+
175
+ # 3b. Compute x * y element-wise for MPFSS
176
+ # Since y[i] = 1, this is just [x, x, ..., x]
177
+ xy = [x for _ in range(self.t)]
178
+
179
+ # Generate MPFSS keys for function f_{S, x}
180
+ # f_{S,xy}(i) = x if i ∈ S, 0 otherwise
181
+ points = list(zip(S, xy))
182
+ key_fss_0, key_fss_1 = self._mpfss.gen(points)
183
+
184
+ # 4. Serialize seeds
185
+ # Seed for LPN matrix (shared via common random string)
186
+ matrix_seed = secrets.token_bytes(32)
187
+
188
+ # seed_sender = (n, n_prime, t, key_fss_0, S, y, matrix_seed)
189
+ seed_sender = self._serialize_sender_seed(key_fss_0, S, y, matrix_seed)
190
+
191
+ # seed_receiver = (n, n_prime, key_fss_1, x, matrix_seed)
192
+ seed_receiver = self._serialize_receiver_seed(key_fss_1, x, matrix_seed)
193
+
194
+ logger.debug("SilentOT gen: t=%d, |S|=%d, x=%d", self.t, len(S), x)
195
+
196
+ return seed_sender, seed_receiver
197
+
198
+ def _serialize_sender_seed(self, key_fss: bytes, S: List[int],
199
+ y: List[int], matrix_seed: bytes) -> bytes:
200
+ """Serialize sender's seed."""
201
+ parts = []
202
+ # Version
203
+ parts.append(SEED_VERSION.to_bytes(2, 'big'))
204
+ # Parameters
205
+ parts.append(self.n.to_bytes(4, 'big'))
206
+ parts.append(self.n_prime.to_bytes(4, 'big'))
207
+ parts.append(self.t.to_bytes(4, 'big'))
208
+ # MPFSS key
209
+ parts.append(len(key_fss).to_bytes(4, 'big'))
210
+ parts.append(key_fss)
211
+ # Sparse positions S
212
+ for pos in S:
213
+ parts.append(pos.to_bytes(4, 'big'))
214
+ # y values
215
+ for val in y:
216
+ parts.append(val.to_bytes(8, 'big'))
217
+ # Matrix seed
218
+ parts.append(matrix_seed)
219
+ return b''.join(parts)
220
+
221
+ def _serialize_receiver_seed(self, key_fss: bytes, x: int,
222
+ matrix_seed: bytes) -> bytes:
223
+ """Serialize receiver's seed."""
224
+ parts = []
225
+ # Version
226
+ parts.append(SEED_VERSION.to_bytes(2, 'big'))
227
+ # Parameters
228
+ parts.append(self.n.to_bytes(4, 'big'))
229
+ parts.append(self.n_prime.to_bytes(4, 'big'))
230
+ parts.append(self.t.to_bytes(4, 'big'))
231
+ # MPFSS key
232
+ parts.append(len(key_fss).to_bytes(4, 'big'))
233
+ parts.append(key_fss)
234
+ # x value
235
+ parts.append(x.to_bytes(8, 'big'))
236
+ # Matrix seed
237
+ parts.append(matrix_seed)
238
+ return b''.join(parts)
239
+
240
+ def _deserialize_sender_seed(self, seed: bytes) -> Tuple:
241
+ """Deserialize sender's seed."""
242
+ offset = 0
243
+ version = int.from_bytes(seed[offset:offset + 2], 'big')
244
+ offset += 2
245
+ if version != SEED_VERSION:
246
+ raise ValueError(f"Unsupported seed version: {version}, expected {SEED_VERSION}")
247
+ n = int.from_bytes(seed[offset:offset + 4], 'big')
248
+ offset += 4
249
+ n_prime = int.from_bytes(seed[offset:offset + 4], 'big')
250
+ offset += 4
251
+ t = int.from_bytes(seed[offset:offset + 4], 'big')
252
+ offset += 4
253
+ key_len = int.from_bytes(seed[offset:offset + 4], 'big')
254
+ offset += 4
255
+ key_fss = seed[offset:offset + key_len]
256
+ offset += key_len
257
+ S = []
258
+ for _ in range(t):
259
+ S.append(int.from_bytes(seed[offset:offset + 4], 'big'))
260
+ offset += 4
261
+ y = []
262
+ for _ in range(t):
263
+ y.append(int.from_bytes(seed[offset:offset + 8], 'big'))
264
+ offset += 8
265
+ matrix_seed = seed[offset:offset + 32]
266
+ return n, n_prime, t, key_fss, S, y, matrix_seed
267
+
268
+ def _deserialize_receiver_seed(self, seed: bytes) -> Tuple:
269
+ """Deserialize receiver's seed."""
270
+ offset = 0
271
+ version = int.from_bytes(seed[offset:offset + 2], 'big')
272
+ offset += 2
273
+ if version != SEED_VERSION:
274
+ raise ValueError(f"Unsupported seed version: {version}, expected {SEED_VERSION}")
275
+ n = int.from_bytes(seed[offset:offset + 4], 'big')
276
+ offset += 4
277
+ n_prime = int.from_bytes(seed[offset:offset + 4], 'big')
278
+ offset += 4
279
+ t = int.from_bytes(seed[offset:offset + 4], 'big')
280
+ offset += 4
281
+ key_len = int.from_bytes(seed[offset:offset + 4], 'big')
282
+ offset += 4
283
+ key_fss = seed[offset:offset + key_len]
284
+ offset += key_len
285
+ x = int.from_bytes(seed[offset:offset + 8], 'big')
286
+ offset += 8
287
+ matrix_seed = seed[offset:offset + 32]
288
+ return n, n_prime, t, key_fss, x, matrix_seed
289
+
290
+ def expand_sender(self, seed: bytes) -> Tuple[List[int], List[bytes]]:
291
+ """
292
+ Expand sender's seed to get (choice_bits, messages).
293
+
294
+ Simplified implementation that works directly on domain points:
295
+ - Sender knows sparse positions S where choice bit = 1
296
+ - For each position i in [n], choice_bit[i] = 1 iff i ∈ S
297
+ - MPFSS shares f where f(i) = x for i ∈ S, 0 otherwise
298
+ - v0[i] is sender's share, with v0[i] + v1[i] = f(i)
299
+
300
+ OT correlation:
301
+ - Sender outputs: (choice_bits, messages) where message[i] = H(i, -v0[i])
302
+ - Receiver outputs: (m0, m1) where m0 = H(i, v1[i]), m1 = H(i, v1[i] - x)
303
+ - When choice=0 (i ∉ S): f(i)=0, so v0+v1=0, thus -v0=v1, so sender_msg = m0 ✓
304
+ - When choice=1 (i ∈ S): f(i)=x, so v0+v1=x, thus -v0=v1-x, so sender_msg = m1 ✓
305
+
306
+ Parameters
307
+ ----------
308
+ seed : bytes
309
+ Sender's seed from gen()
310
+
311
+ Returns
312
+ -------
313
+ Tuple[List[int], List[bytes]]
314
+ (choice_bits, messages) where:
315
+ - choice_bits[i] is 0 or 1
316
+ - messages[i] is 32-byte message
317
+ """
318
+ n, n_prime, t, key_fss, S, y, matrix_seed = self._deserialize_sender_seed(seed)
319
+
320
+ # Compute MPFSS full evaluation: v0 (sender's share)
321
+ v0 = self._mpfss.full_eval(0, key_fss)
322
+
323
+ # Choice bits: 1 for positions in S, 0 otherwise
324
+ S_set = set(S)
325
+ choice_bits = [1 if i in S_set else 0 for i in range(self.n)]
326
+
327
+ # Messages: H(i, -v0[i]) for each i
328
+ # This matches receiver's m_{choice[i]} due to MPFSS correlation
329
+ messages = []
330
+ for i in range(self.n):
331
+ neg_v0_i = (-v0[i]) % MODULUS
332
+ msg = self.correlation_robust_hash(i, neg_v0_i)
333
+ messages.append(msg)
334
+
335
+ logger.debug("SilentOT expand_sender: n=%d, sum(choice_bits)=%d",
336
+ self.n, sum(choice_bits))
337
+
338
+ return choice_bits, messages
339
+
340
+ def expand_receiver(self, seed: bytes) -> List[Tuple[bytes, bytes]]:
341
+ """
342
+ Expand receiver's seed to get both messages for each OT.
343
+
344
+ Simplified implementation:
345
+ - Receiver has MPFSS key that shares f where f(i) = x for i ∈ S, 0 otherwise
346
+ - v1[i] is receiver's share, with v0[i] + v1[i] = f(i)
347
+
348
+ For each OT i:
349
+ - m0 = H(i, v1[i]) -- matches sender when choice=0 (f(i)=0, v1=-v0)
350
+ - m1 = H(i, v1[i] - x) -- matches sender when choice=1 (f(i)=x, v1-x=-v0)
351
+
352
+ Parameters
353
+ ----------
354
+ seed : bytes
355
+ Receiver's seed from gen()
356
+
357
+ Returns
358
+ -------
359
+ List[Tuple[bytes, bytes]]
360
+ List of (m0, m1) tuples for each OT
361
+ """
362
+ n, n_prime, t, key_fss, x, matrix_seed = self._deserialize_receiver_seed(seed)
363
+
364
+ # Compute MPFSS full evaluation: v1 (receiver's share)
365
+ v1 = self._mpfss.full_eval(1, key_fss)
366
+
367
+ # Generate both messages for each OT
368
+ messages = []
369
+ for i in range(self.n):
370
+ # m0 = H(i, v1[i]) - for when choice = 0
371
+ m0 = self.correlation_robust_hash(i, v1[i])
372
+ # m1 = H(i, v1[i] - x) - for when choice = 1
373
+ m1 = self.correlation_robust_hash(i, (v1[i] - x) % MODULUS)
374
+ messages.append((m0, m1))
375
+
376
+ logger.debug("SilentOT expand_receiver: n=%d", self.n)
377
+
378
+ return messages