@@ -567,7 +567,7 @@ public enum HeAPITestHelpers {
567567 try await ciphertextProduct2 *= ciphertext2
568568
569569 var relinearizedProd = ciphertextProduct
570- try relinearizedProd. relinearize ( using: #require( testEnv. evaluationKey) )
570+ try await relinearizedProd. relinearize ( using: #require( testEnv. evaluationKey) )
571571 #expect( relinearizedProd. polys. count == Scheme . freshCiphertextPolyCount)
572572
573573 let coeffCiphertext = try await ciphertextProduct. convertToCoeffFormat ( )
@@ -1233,7 +1233,7 @@ public enum HeAPITestHelpers {
12331233 // with mod-switch down
12341234 if context. coefficientModuli. count > 2 {
12351235 var ciphertext = testEnv. ciphertext1
1236- try ciphertext. modSwitchDown ( )
1236+ try await ciphertext. modSwitchDown ( )
12371237 let evalCiphertext = try await ciphertext. convertToEvalFormat ( )
12381238 let moduliCount = evalCiphertext. moduli. count
12391239 let evalPlaintext = try testEnv. context. encode ( values: data2, format: . simd, moduliCount: moduliCount)
@@ -1253,84 +1253,108 @@ public enum HeAPITestHelpers {
12531253 context: Scheme . Context ,
12541254 scheme _: Scheme . Type ) async throws
12551255 {
1256- func runRotationTest( context: Scheme . Context , galoisElements: [ Int ] , multiStep: Bool ) async throws {
1257- let degree = context. degree
1256+ func runRotationTestSync( context: Scheme . Context , galoisElements: [ Int ] , multiStep: Bool ) throws {
12581257 let testEnv = try TestEnv < Scheme > ( context: context, format: . simd, galoisElements: galoisElements)
12591258 let evaluationKey = try #require( testEnv. evaluationKey)
1259+ let degree = context. degree
1260+
12601261 for step in 1 ..< min ( 8 , degree / 2 ) {
12611262 let expectedData = Array ( testEnv. data1 [ degree / 2 - step..< degree / 2 ] + testEnv
12621263 . data1 [ 0 ..< degree / 2 - step] + testEnv
12631264 . data1 [ degree - step..< degree] + testEnv. data1 [ degree / 2 ..< degree - step] )
12641265 var rotatedCiphertext = testEnv. ciphertext1
1265- var rotatedCiphertextAsync = testEnv. ciphertext1
12661266 if multiStep {
12671267 try rotatedCiphertext. rotateColumnsMultiStep ( by: step, using: evaluationKey)
1268- try await Scheme . rotateColumnsMultiStepAsync (
1269- of: & rotatedCiphertextAsync,
1270- by: step,
1271- using: evaluationKey)
12721268 } else {
12731269 try rotatedCiphertext. rotateColumns ( by: step, using: evaluationKey)
1274- try await Scheme . rotateColumnsAsync ( of: & rotatedCiphertextAsync, by: step, using: evaluationKey)
12751270 }
12761271 try testEnv. checkDecryptsDecodes ( ciphertext: rotatedCiphertext, format: . simd, expected: expectedData)
1277- try testEnv. checkDecryptsDecodes (
1278- ciphertext: rotatedCiphertextAsync,
1279- format: . simd,
1280- expected: expectedData)
12811272
12821273 if multiStep {
12831274 try rotatedCiphertext. rotateColumnsMultiStep ( by: - step, using: evaluationKey)
1284- try await Scheme . rotateColumnsMultiStepAsync (
1285- of: & rotatedCiphertextAsync,
1286- by: - step,
1287- using: evaluationKey)
12881275 } else {
12891276 try rotatedCiphertext. rotateColumns ( by: - step, using: evaluationKey)
1290- try await Scheme . rotateColumnsAsync ( of: & rotatedCiphertextAsync, by: - step, using: evaluationKey)
12911277 }
1292- try testEnv. checkDecryptsDecodes ( ciphertext: rotatedCiphertext,
1293- format: . simd,
1294- expected: testEnv. data1)
1295- try testEnv. checkDecryptsDecodes ( ciphertext: rotatedCiphertextAsync,
1296- format: . simd,
1297- expected: testEnv. data1)
1278+ try testEnv. checkDecryptsDecodes ( ciphertext: rotatedCiphertext, format: . simd, expected: testEnv. data1)
1279+ }
1280+ }
1281+
1282+ func runRotationTestAsync( context: Scheme . Context , galoisElements: [ Int ] , multiStep: Bool ) async throws {
1283+ let testEnv = try TestEnv < Scheme > ( context: context, format: . simd, galoisElements: galoisElements)
1284+ let evaluationKey = try #require( testEnv. evaluationKey)
1285+ let degree = context. degree
1286+
1287+ for step in 1 ..< min ( 8 , degree / 2 ) {
1288+ let expectedData = Array ( testEnv. data1 [ degree / 2 - step..< degree / 2 ] + testEnv
1289+ . data1 [ 0 ..< degree / 2 - step] + testEnv
1290+ . data1 [ degree - step..< degree] + testEnv. data1 [ degree / 2 ..< degree - step] )
1291+ var rotatedCiphertext = testEnv. ciphertext1
1292+ if multiStep {
1293+ try await rotatedCiphertext. rotateColumnsMultiStep ( by: step, using: evaluationKey)
1294+ } else {
1295+ try await rotatedCiphertext. rotateColumns ( by: step, using: evaluationKey)
1296+ }
1297+ try testEnv. checkDecryptsDecodes ( ciphertext: rotatedCiphertext, format: . simd, expected: expectedData)
1298+
1299+ if multiStep {
1300+ try await rotatedCiphertext. rotateColumnsMultiStep ( by: - step, using: evaluationKey)
1301+ } else {
1302+ try await rotatedCiphertext. rotateColumns ( by: - step, using: evaluationKey)
1303+ }
1304+ try testEnv. checkDecryptsDecodes ( ciphertext: rotatedCiphertext, format: . simd, expected: testEnv. data1)
12981305 }
12991306 }
13001307
13011308 guard context. supportsSimdEncoding, context. supportsEvaluationKey else {
13021309 return
13031310 }
13041311
1312+ let degree = context. degree
1313+ let galoisElementsRotate = try ( 1 ..< ( degree >> 1 ) ) . flatMap { step in
1314+ try [
1315+ GaloisElement . rotatingColumns ( by: step, degree: degree) ,
1316+ GaloisElement . rotatingColumns ( by: - step, degree: degree) ,
1317+ ]
1318+ }
1319+ let galoisElementsMultiStep = try GaloisElement . rotatingColumnsMultiStep ( degree: degree)
1320+
1321+ try runRotationTestSync ( context: context, galoisElements: galoisElementsRotate, multiStep: false )
1322+ try await runRotationTestAsync ( context: context, galoisElements: galoisElementsMultiStep, multiStep: true )
1323+ }
1324+
1325+ /// Testing ciphertext rotation of the scheme.
1326+ @inlinable
1327+ public static func schemeSwapRowsTest< Scheme: HeScheme > (
1328+ context: Scheme . Context ,
1329+ scheme _: Scheme . Type ) async throws
1330+ {
1331+ guard context. supportsSimdEncoding, context. supportsEvaluationKey else {
1332+ return
1333+ }
13051334 let degree = context. degree
13061335 let galoisElementsSwap = [ GaloisElement . swappingRows ( degree: degree) ]
13071336 let testEnv = try TestEnv < Scheme > ( context: context, format: . simd, galoisElements: galoisElementsSwap)
13081337 let evaluationKey = try #require( testEnv. evaluationKey)
13091338 let expectedData = Array ( testEnv. data1 [ degree / 2 ..< degree] + testEnv. data1 [ 0 ..< degree / 2 ] )
13101339 var ciphertext = testEnv. ciphertext1
1311- var ciphertextAsync = ciphertext
13121340
1313- try ciphertext. swapRows ( using: evaluationKey)
1314- try await Scheme . swapRowsAsync ( of: & ciphertextAsync, using: evaluationKey)
1341+ func swapRowsSyncTest( ) throws {
1342+ try ciphertext. swapRows ( using: evaluationKey)
1343+ try testEnv. checkDecryptsDecodes ( ciphertext: ciphertext, format: . simd, expected: expectedData)
13151344
1316- try testEnv. checkDecryptsDecodes ( ciphertext: ciphertext, format: . simd, expected: expectedData)
1317- try testEnv. checkDecryptsDecodes ( ciphertext: ciphertextAsync, format: . simd, expected: expectedData)
1345+ try ciphertext. swapRows ( using: evaluationKey)
1346+ try testEnv. checkDecryptsDecodes ( ciphertext: ciphertext, format: . simd, expected: testEnv. data1)
1347+ }
1348+ try swapRowsSyncTest ( )
13181349
1319- try ciphertext. swapRows ( using: evaluationKey)
1320- try await Scheme . swapRowsAsync ( of: & ciphertextAsync, using: evaluationKey)
1321- try testEnv. checkDecryptsDecodes ( ciphertext: ciphertext, format: . simd, expected: testEnv. data1)
1322- try testEnv. checkDecryptsDecodes ( ciphertext: ciphertextAsync, format: . simd, expected: testEnv. data1)
1350+ func swapRowsAsyncTest( ) async throws {
1351+ try await ciphertext. swapRows ( using: evaluationKey)
1352+ try testEnv. checkDecryptsDecodes ( ciphertext: ciphertext, format: . simd, expected: expectedData)
13231353
1324- let galoisElementsRotate = try ( 1 ..< ( degree >> 1 ) ) . flatMap { step in
1325- try [
1326- GaloisElement . rotatingColumns ( by: step, degree: degree) ,
1327- GaloisElement . rotatingColumns ( by: - step, degree: degree) ,
1328- ]
1354+ try await ciphertext. swapRows ( using: evaluationKey)
1355+ try testEnv. checkDecryptsDecodes ( ciphertext: ciphertext, format: . simd, expected: testEnv. data1)
13291356 }
1330- let galoisElementsMultiStep = try GaloisElement . rotatingColumnsMultiStep ( degree: degree)
1331-
1332- try await runRotationTest ( context: context, galoisElements: galoisElementsRotate, multiStep: false )
1333- try await runRotationTest ( context: context, galoisElements: galoisElementsMultiStep, multiStep: true )
1357+ try await swapRowsAsyncTest ( )
13341358 }
13351359
13361360 /// Testing apply Galois element of the scheme.
@@ -1358,25 +1382,37 @@ public enum HeAPITestHelpers {
13581382
13591383 let dataCount = testEnv. data1. count
13601384 let halfDataCount = dataCount / 2
1361- for (step, element) in elements. enumerated ( ) {
1362- for modSwitchCount in 0 ... max ( 0 , context. coefficientModuli. count - 2 ) {
1363- var rotatedCiphertext = testEnv. ciphertext1
1364- var rotatedCiphertextAsync = testEnv. ciphertext1
1385+ func syncTest( ) throws {
1386+ for (step, element) in elements. enumerated ( ) {
1387+ for modSwitchCount in 0 ... max ( 0 , context. coefficientModuli. count - 2 ) {
1388+ var rotatedCiphertext = testEnv. ciphertext1
1389+
1390+ for _ in 0 ..< modSwitchCount {
1391+ try rotatedCiphertext. modSwitchDown ( )
1392+ }
1393+ try rotatedCiphertext. applyGalois ( element: element, using: evaluationKey)
1394+ let expected = rotate ( original: testEnv. data1, halfDataCount: halfDataCount, step: step + 1 )
1395+ try testEnv. checkDecryptsDecodes ( ciphertext: rotatedCiphertext, format: . simd, expected: expected)
1396+ }
1397+ }
1398+ }
1399+ try syncTest ( )
13651400
1366- for _ in 0 ..< modSwitchCount {
1367- try rotatedCiphertext. modSwitchDown ( )
1368- try await Scheme . modSwitchDownAsync ( & rotatedCiphertextAsync)
1401+ func asyncTest( ) async throws {
1402+ for (step, element) in elements. enumerated ( ) {
1403+ for modSwitchCount in 0 ... max ( 0 , context. coefficientModuli. count - 2 ) {
1404+ var rotatedCiphertext = testEnv. ciphertext1
1405+
1406+ for _ in 0 ..< modSwitchCount {
1407+ try await rotatedCiphertext. modSwitchDown ( )
1408+ }
1409+ try await rotatedCiphertext. applyGalois ( element: element, using: evaluationKey)
1410+ let expected = rotate ( original: testEnv. data1, halfDataCount: halfDataCount, step: step + 1 )
1411+ try testEnv. checkDecryptsDecodes ( ciphertext: rotatedCiphertext, format: . simd, expected: expected)
13691412 }
1370- try rotatedCiphertext. applyGalois ( element: element, using: evaluationKey)
1371- try await Scheme . applyGaloisAsync (
1372- ciphertext: & rotatedCiphertextAsync,
1373- element: element,
1374- using: evaluationKey)
1375- let expected = rotate ( original: testEnv. data1, halfDataCount: halfDataCount, step: step + 1 )
1376- try testEnv. checkDecryptsDecodes ( ciphertext: rotatedCiphertext, format: . simd, expected: expected)
1377- try testEnv. checkDecryptsDecodes ( ciphertext: rotatedCiphertextAsync, format: . simd, expected: expected)
13781413 }
13791414 }
1415+ try await asyncTest ( )
13801416 }
13811417
13821418 /// Testing noise budget estimation.
0 commit comments