### Generate Local Documentation with pkgsite Source: https://github.com/tuneinsight/lattigo/blob/main/README.md Use the `pkgsite` tool to generate and open local documentation for the Lattigo library. Ensure `pkgsite` is installed globally. ```bash go install golang.org/x/pkgsite/cmd/pkgsite@latest cd lattigo pkgsite -open . ``` -------------------------------- ### CKKS Homomorphic Operations Example Source: https://context7.com/tuneinsight/lattigo/llms.txt This example showcases various homomorphic operations including scalar addition, vector addition, scalar multiplication, ciphertext-ciphertext multiplication with relinearization, slot rotation, and complex conjugation. Ensure proper parameter setup and key generation before performing these operations. Rescaling is crucial after multiplication to manage ciphertext noise. ```go package main import ( "fmt" "github.com/tuneinsight/lattigo/v6/core/rlwe" "github.com/tuneinsight/lattigo/v6/schemes/ckks" ) func main() { params, _ := ckks.NewParametersFromLiteral(ckks.ParametersLiteral{ LogN: 14, LogQ: []int{55, 45, 45, 45, 45, 45, 45, 45}, LogP: []int{61}, LogDefaultScale: 45, }) kgen := rlwe.NewKeyGenerator(params) sk := kgen.GenSecretKeyNew() pk := kgen.GenPublicKeyNew(sk) rlk := kgen.GenRelinearizationKeyNew(sk) // Generate rotation keys rotKey := kgen.GenGaloisKeyNew(params.GaloisElement(5), sk) conjKey := kgen.GenGaloisKeyNew(params.GaloisElementForComplexConjugation(), sk) evk := rlwe.NewMemEvaluationKeySet(rlk, rotKey, conjKey) encoder := ckks.NewEncoder(params) encryptor := rlwe.NewEncryptor(params, pk) decryptor := rlwe.NewDecryptor(params, sk) eval := ckks.NewEvaluator(params, evk) // Encrypt test values values := []float64{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0} pt := ckks.NewPlaintext(params, params.MaxLevel()) encoder.Encode(values, pt) ct, _ := encryptor.EncryptNew(pt) // Addition with scalar ctAddScalar, _ := eval.AddNew(ct, 10.0) // Addition with vector (encoded at matching scale) addVec := []float64{0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8} ctAddVec, _ := eval.AddNew(ct, addVec) // Multiplication with scalar ctMulScalar, _ := eval.MulNew(ct, 2.0) // Ciphertext-ciphertext multiplication (consumes a level) ctSquared, _ := eval.MulRelinNew(ct, ct) eval.Rescale(ctSquared, ctSquared) // Slot rotation by 5 positions to the left ctRotated, _ := eval.RotateNew(ct, 5) // Complex conjugation ctConjugate, _ := eval.ConjugateNew(ct) // Decrypt and verify rotation ptRotated := decryptor.DecryptNew(ctRotated) resultRotated := make([]float64, 8) encoder.Decode(ptRotated, resultRotated) fmt.Printf("Original: %v\n", values) fmt.Printf("Rotated: %v\n", resultRotated[:8]) _ = ctAddScalar _ = ctAddVec _ = ctMulScalar _ = ctConjugate } ``` -------------------------------- ### Homomorphic Matrix-Vector Multiplication in Go Source: https://context7.com/tuneinsight/lattigo/llms.txt This Go code snippet demonstrates a full matrix-vector multiplication on encrypted data using the Lattigo library. It includes parameter setup, key generation, encoding of a sparse matrix (represented by diagonals) and a vector, and the homomorphic evaluation of the transformation. Ensure Lattigo is installed and configured. ```go package main import ( "fmt" "math/rand" "github.com/tuneinsight/lattigo/v6/circuits/ckks/lintrans" "github.com/tuneinsight/lattigo/v6/core/rlwe" "github.com/tuneinsight/lattigo/v6/schemes/ckks" ) func main() { params, _ := ckks.NewParametersFromLiteral(ckks.ParametersLiteral{ LogN: 14, LogQ: []int{55, 45, 45, 45, 45, 45, 45, 45}, LogP: []int{61}, LogDefaultScale: 45, }) kgen := rlwe.NewKeyGenerator(params) sk := kgen.GenSecretKeyNew() rlk := kgen.GenRelinearizationKeyNew(sk) encoder := ckks.NewEncoder(params) encryptor := rlwe.NewEncryptor(params, sk) eval := ckks.NewEvaluator(params, rlwe.NewMemEvaluationKeySet(rlk)) slots := params.MaxSlots() // Define matrix as diagonals (sparse representation) // Non-zero diagonals at indices -1, 0, 1 (tridiagonal matrix) diagonals := make(lintrans.Diagonals[complex128]) for _, diagIdx := range []int{-1, 0, 1} { diag := make([]complex128, slots) for j := range diag { diag[j] = complex(rand.Float64(), 0) } diagonals[diagIdx] = diag } // Encrypt input vector values := make([]complex128, slots) for i := range values { values[i] = complex(rand.Float64(), 0) } pt := ckks.NewPlaintext(params, params.MaxLevel()) encoder.Encode(values, pt) ct, _ := encryptor.EncryptNew(pt) // Configure linear transformation parameters ltParams := lintrans.Parameters{ DiagonalsIndexList: diagonals.DiagonalsIndexList(), LevelQ: ct.Level(), LevelP: params.MaxLevelP(), Scale: rlwe.NewScale(params.Q()[ct.Level()]), LogDimensions: ct.LogDimensions, LogBabyStepGiantStepRatio: 1, } // Encode linear transformation lt := lintrans.NewTransformation(params, ltParams) lintrans.Encode(encoder, diagonals, lt) // Generate required Galois keys galEls := lintrans.GaloisElements(params, ltParams) galKeys := kgen.GenGaloisKeysNew(galEls, sk) evalWithKeys := eval.WithKey(rlwe.NewMemEvaluationKeySet(rlk, galKeys...)) // Evaluate linear transformation ltEval := lintrans.NewEvaluator(evalWithKeys) ctResult := ckks.NewCiphertext(params, 1, ct.Level()-1) ltEval.Evaluate(ct, lt, ctResult) evalWithKeys.Rescale(ctResult, ctResult) fmt.Println("Matrix-vector multiplication completed on encrypted data") } ``` -------------------------------- ### Key Generation - Secret, Public, and Evaluation Keys Source: https://context7.com/tuneinsight/lattigo/llms.txt Generates various cryptographic keys required for homomorphic operations, including secret, public, relinearization, and Galois keys. This setup is common across different schemes like CKKS and BGV/BFV. ```go package main import ( "github.com/tuneinsight/lattigo/v6/core/rlwe" "github.com/tuneinsight/lattigo/v6/schemes/ckks" ) func main() { params, _ := ckks.NewParametersFromLiteral(ckks.ParametersLiteral{ LogN: 14, LogQ: []int{55, 45, 45, 45, 45, 45, 45, 45}, LogP: []int{61}, LogDefaultScale: 45, }) // Create key generator kgen := rlwe.NewKeyGenerator(params) // Generate secret key (private, never shared) sk := kgen.GenSecretKeyNew() // Generate public encryption key (can be shared publicly) pk := kgen.GenPublicKeyNew(sk) // Generate relinearization key (for ciphertext multiplication) rlk := kgen.GenRelinearizationKeyNew(sk) // Generate Galois keys for specific rotations rotations := []int{1, 2, 4, 8, 16, 32} // Rotation amounts galoisElements := make([]uint64, len(rotations)) for i, rot := range rotations { galoisElements[i] = params.GaloisElement(rot) } galoisKeys := kgen.GenGaloisKeysNew(galoisElements, sk) // Generate Galois key for complex conjugation (CKKS only) conjElement := params.GaloisElementForComplexConjugation() conjKey := kgen.GenGaloisKeyNew(conjElement, sk) // Create evaluation key set combining all keys evk := rlwe.NewMemEvaluationKeySet(rlk, append(galoisKeys, conjKey)...) // Use with evaluator eval := ckks.NewEvaluator(params, evk) _ = eval // Ready for homomorphic operations } ``` -------------------------------- ### Perform CKKS Homomorphic Arithmetic Source: https://context7.com/tuneinsight/lattigo/llms.txt Demonstrates setting up CKKS parameters, key generation, encoding, encryption, and basic homomorphic operations like addition and multiplication with rescaling. ```go package main import ( "fmt" "math/rand" "github.com/tuneinsight/lattigo/v6/core/rlwe" "github.com/tuneinsight/lattigo/v6/schemes/ckks" ) func main() { // Create 128-bit secure parameters with depth-7 circuit capacity params, err := ckks.NewParametersFromLiteral(ckks.ParametersLiteral{ LogN: 14, // Ring degree 2^14 = 16384 LogQ: []int{55, 45, 45, 45, 45, 45, 45, 45}, // Ciphertext modulus primes LogP: []int{61}, // Key-switching auxiliary prime LogDefaultScale: 45, // Scaling factor 2^45 }) if err != nil { panic(err) } // Generate keys kgen := rlwe.NewKeyGenerator(params) sk := kgen.GenSecretKeyNew() pk := kgen.GenPublicKeyNew(sk) rlk := kgen.GenRelinearizationKeyNew(sk) evk := rlwe.NewMemEvaluationKeySet(rlk) // Create encoder, encryptor, decryptor, evaluator encoder := ckks.NewEncoder(params) encryptor := rlwe.NewEncryptor(params, pk) decryptor := rlwe.NewDecryptor(params, sk) evaluator := ckks.NewEvaluator(params, evk) // Prepare plaintext values (complex numbers in [-1, 1]) slots := params.MaxSlots() // N/2 slots for complex, N for real values1 := make([]float64, slots) values2 := make([]float64, slots) for i := range values1 { values1[i] = 2*rand.Float64() - 1 values2[i] = 2*rand.Float64() - 1 } // Encode and encrypt pt1 := ckks.NewPlaintext(params, params.MaxLevel()) pt2 := ckks.NewPlaintext(params, params.MaxLevel()) encoder.Encode(values1, pt1) encoder.Encode(values2, pt2) ct1, _ := encryptor.EncryptNew(pt1) ct2, _ := encryptor.EncryptNew(pt2) // Homomorphic addition ctAdd, _ := evaluator.AddNew(ct1, ct2) // Homomorphic multiplication with relinearization ctMul, _ := evaluator.MulRelinNew(ct1, ct2) evaluator.Rescale(ctMul, ctMul) // Rescale to control scale growth // Decrypt and decode results ptResult := decryptor.DecryptNew(ctAdd) result := make([]float64, slots) encoder.Decode(ptResult, result) fmt.Printf("Original: %.6f + %.6f = %.6f\n", values1[0], values2[0], values1[0]+values2[0]) fmt.Printf("Decrypted: %.6f\n", result[0]) } ``` -------------------------------- ### Perform Collective Key Switching with BGV Source: https://context7.com/tuneinsight/lattigo/llms.txt Demonstrates the full workflow of generating a collective public key, encrypting data, and switching the ciphertext to a receiver's key using the PublicKeySwitchProtocol. ```go package main import ( "fmt" "github.com/tuneinsight/lattigo/v6/core/rlwe" "github.com/tuneinsight/lattigo/v6/multiparty" "github.com/tuneinsight/lattigo/v6/ring" "github.com/tuneinsight/lattigo/v6/schemes/bgv" "github.com/tuneinsight/lattigo/v6/utils/sampling" ) func main() { params, _ := bgv.NewParametersFromLiteral(bgv.ParametersLiteral{ LogN: 14, LogQ: []int{56, 55, 55, 54, 54, 54}, LogP: []int{55, 55}, PlaintextModulus: 65537, }) N := 3 // Number of input parties crs, _ := sampling.NewKeyedPRNG([]byte{'t', 'e', 's', 't'}) // Generate keys for each party kgen := rlwe.NewKeyGenerator(params) secretKeys := make([]*rlwe.SecretKey, N) for i := range secretKeys { secretKeys[i] = kgen.GenSecretKeyNew() } // Generate receiver's key pair (external party) receiverSK, receiverPK := kgen.GenKeyPairNew() // ... (setup phase: generate collective pk, encrypt data, evaluate circuit) // Assume we have an encrypted result 'encResult' under collective key // For demo, create a dummy ciphertext ckg := multiparty.NewPublicKeyGenProtocol(params) ckgShares := make([]multiparty.PublicKeyGenShare, N) for i := range ckgShares { ckgShares[i] = ckg.AllocateShare() } combined := ckg.AllocateShare() crp := ckg.SampleCRP(crs) for i, sk := range secretKeys { ckg.GenShare(sk, crp, &ckgShares[i]) } for _, share := range ckgShares { ckg.AggregateShares(share, combined, &combined) } collectivePK := rlwe.NewPublicKey(params) ckg.GenPublicKey(combined, crp, collectivePK) // Encrypt test data encoder := bgv.NewEncoder(params) encryptor := rlwe.NewEncryptor(params, collectivePK) values := []uint64{42, 43, 44, 45} pt := bgv.NewPlaintext(params, params.MaxLevel()) encoder.Encode(values, pt) encResult, _ := encryptor.EncryptNew(pt) // Public Key Switch Protocol - re-encrypt to receiver's key pcks, _ := multiparty.NewPublicKeySwitchProtocol(params, ring.DiscreteGaussian{Sigma: 1 << 30, Bound: 6 * (1 << 30)}) // Each party generates their share pcksShares := make([]multiparty.PublicKeySwitchShare, N) for i := range pcksShares { pcksShares[i] = pcks.AllocateShare(params.MaxLevel()) } for i, sk := range secretKeys { pcks.GenShare(sk, receiverPK, encResult, &pcksShares[i]) } // Aggregate shares pcksCombined := pcks.AllocateShare(params.MaxLevel()) for _, share := range pcksShares { pcks.AggregateShares(share, pcksCombined, &pcksCombined) } // Switch key - output encrypted under receiver's key encOut := bgv.NewCiphertext(params, 1, params.MaxLevel()) pcks.KeySwitch(encResult, pcksCombined, encOut) // Receiver decrypts with their secret key decryptor := rlwe.NewDecryptor(params, receiverSK) ptResult := decryptor.DecryptNew(encOut) result := make([]uint64, params.MaxSlots()) encoder.Decode(ptResult, result) fmt.Printf("Original: %v\n", values) fmt.Printf("Decrypted by receiver: %v\n", result[:4]) } ``` -------------------------------- ### BGV/BFV Scheme - Exact Modular Arithmetic Source: https://context7.com/tuneinsight/lattigo/llms.txt Demonstrates exact homomorphic operations (addition and multiplication) using the BGV/BFV scheme. Requires setting parameters, generating keys, encoding plaintext, encrypting, performing operations, and decrypting results. Operations are exact within plaintext modulus bounds. ```go package main import ( "fmt" "math/rand" "github.com/tuneinsight/lattigo/v6/core/rlwe" "github.com/tuneinsight/lattigo/v6/schemes/bgv" ) func main() { // Create parameters with plaintext modulus T = 65537 params, err := bgv.NewParametersFromLiteral(bgv.ParametersLiteral{ LogN: 14, // Ring degree LogQ: []int{55, 45, 45, 45, 45, 45, 45, 45}, // Ciphertext modulus LogP: []int{61}, // Auxiliary modulus PlaintextModulus: 0x10001, // T = 65537 }) if err != nil { panic(err) } // Generate keys kgen := rlwe.NewKeyGenerator(params) sk := kgen.GenSecretKeyNew() pk := kgen.GenPublicKeyNew(sk) rlk := kgen.GenRelinearizationKeyNew(sk) evk := rlwe.NewMemEvaluationKeySet(rlk) // Create encoder, encryptor, decryptor, evaluator encoder := bgv.NewEncoder(params) encryptor := rlwe.NewEncryptor(params, pk) decryptor := rlwe.NewDecryptor(params, sk) evaluator := bgv.NewEvaluator(params, evk) // Prepare integer values (mod T) T := params.PlaintextModulus() slots := params.MaxSlots() values1 := make([]uint64, slots) values2 := make([]uint64, slots) for i := range values1 { values1[i] = rand.Uint64() % T values2[i] = rand.Uint64() % T } // Encode and encrypt pt1 := bgv.NewPlaintext(params, params.MaxLevel()) pt2 := bgv.NewPlaintext(params, params.MaxLevel()) encoder.Encode(values1, pt1) encoder.Encode(values2, pt2) ct1, _ := encryptor.EncryptNew(pt1) ct2, _ := encryptor.EncryptNew(pt2) // Homomorphic operations (exact modular arithmetic) ctAdd, _ := evaluator.AddNew(ct1, ct2) // Addition mod T ctMul, _ := evaluator.MulRelinNew(ct1, ct2) // Multiplication mod T evaluator.Rescale(ctMul, ctMul) // Decrypt and decode ptResult := decryptor.DecryptNew(ctAdd) result := make([]uint64, slots) encoder.Decode(ptResult, result) expected := (values1[0] + values2[0]) % T fmt.Printf("(%d + %d) mod %d = %d\n", values1[0], values2[0], T, expected) fmt.Printf("Decrypted: %d\n", result[0]) } ``` -------------------------------- ### Low-Level Polynomial Arithmetic with NTT Source: https://context7.com/tuneinsight/lattigo/llms.txt Illustrates ring operations and polynomial arithmetic using NTT (Number Theoretic Transform) for efficient computation in Lattigo. This is fundamental for cryptographic operations. ```go package main import ( "fmt" "github.com/tuneinsight/lattigo/v6/ring" ) func main() { // Create a ring Z_Q[X]/(X^N + 1) with N=2^12 and two 60-bit primes logN := 12 N := 1 << logN primes := []uint64{0xFFFFFFFFFC001, 0xFFFFFFFFF8001} // Two ~60-bit NTT primes r, _ := ring.NewRing(N, primes) // Allocate polynomials p1 := r.NewPoly() p2 := r.NewPoly() pResult := r.NewPoly() // Set coefficients (in RNS representation) for i := 0; i < N; i++ { for j := range primes { p1.At(j)[i] = uint64(i) % primes[j] p2.At(j)[i] = uint64(2*i) % primes[j] } } // Transform to NTT domain for fast multiplication r.NTT(p1, p1) r.NTT(p2, p2) // Multiply in NTT domain (coefficient-wise) r.MulCoeffsBarrett(p1, p2, pResult) // Transform back from NTT domain r.INTT(pResult, pResult) // Addition (works in both domains) r.Add(p1, p2, pResult) // Subtraction r.Sub(p1, p2, pResult) // Scalar multiplication r.MulScalar(p1, 5, pResult) fmt.Printf("Ring degree N: %d\n", r.N()) fmt.Printf("Number of primes (RNS components): %d\n", r.ModuliChainLength()) fmt.Printf("Total modulus bits: %d\n", r.LogModuli()) } ``` -------------------------------- ### Evaluate SiLU Function using Chebyshev Approximation Source: https://context7.com/tuneinsight/lattigo/llms.txt This Go code demonstrates evaluating the SiLU activation function on encrypted data using Chebyshev approximation. It requires setting up CKKS parameters, keys, and an encoder, then applying the approximation and evaluating the polynomial. Compare the decrypted results with the expected values. ```go package main import ( "fmt" "math/cmplx" "github.com/tuneinsight/lattigo/v6/circuits/ckks/polynomial" "github.com/tuneinsight/lattigo/v6/core/rlwe" "github.com/tuneinsight/lattigo/v6/schemes/ckks" "github.com/tuneinsight/lattigo/v6/utils/bignum" ) func main() { params, _ := ckks.NewParametersFromLiteral(ckks.ParametersLiteral{ LogN: 14, LogQ: []int{55, 45, 45, 45, 45, 45, 45, 45}, LogP: []int{61}, LogDefaultScale: 45, }) kgen := rlwe.NewKeyGenerator(params) sk := kgen.GenSecretKeyNew() rlk := kgen.GenRelinearizationKeyNew(sk) evk := rlwe.NewMemEvaluationKeySet(rlk) encoder := ckks.NewEncoder(params) encryptor := rlwe.NewEncryptor(params, sk) decryptor := rlwe.NewDecryptor(params, sk) eval := ckks.NewEvaluator(params, evk) // Define the SiLU activation function to approximate SiLU := func(x complex128) complex128 { return x / (cmplx.Exp(-x) + 1) } // Create Chebyshev approximation in interval [-8, 8] with degree 63 prec := params.EncodingPrecision() interval := bignum.Interval{ Nodes: 63, // Polynomial degree A: *bignum.NewFloat(-8, prec), B: *bignum.NewFloat(8, prec), } poly := bignum.ChebyshevApproximation(SiLU, interval) // Encrypt input values values := []float64{-2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0} pt := ckks.NewPlaintext(params, params.MaxLevel()) encoder.Encode(values, pt) ct, _ := encryptor.EncryptNew(pt) // Apply change of basis for Chebyshev evaluation: y = (2*x - a - b)/(b - a) scalarmul, scalaradd := poly.ChangeOfBasis() ctChebyshev, _ := eval.MulNew(ct, scalarmul) eval.Add(ctChebyshev, scalaradd, ctChebyshev) eval.Rescale(ctChebyshev, ctChebyshev) // Evaluate polynomial polyEval := polynomial.NewEvaluator(params, eval) ctResult, _ := polyEval.Evaluate(ctChebyshev, poly, params.DefaultScale()) // Decrypt and compare ptResult := decryptor.DecryptNew(ctResult) result := make([]float64, 8) encoder.Decode(ptResult, result) fmt.Println("SiLU evaluation on encrypted data:") for i, v := range values[:8] { expected := real(SiLU(complex(v, 0))) fmt.Printf(" SiLU(%.1f) = %.6f (expected: %.6f)\n", v, result[i], expected) } } ``` -------------------------------- ### Define BFV Parameters Source: https://github.com/tuneinsight/lattigo/blob/main/schemes/bfv/README.md Parameters used to instantiate the BFV scheme for noise growth verification. ```go ParametersLiteral{ LogN: 14, Q: []uint64{0x3fffffa8001, 0x1000090001, 0x10000c8001, 0x10000f0001, 0xffff00001}, P: []uint64{0x7fffffd8001}, T: 0xf60001, } ``` -------------------------------- ### Perform CKKS Bootstrapping Source: https://context7.com/tuneinsight/lattigo/llms.txt Refreshes a ciphertext at level 0 to a higher level to allow further computation. Requires significant memory for evaluation keys. ```go package main import ( "fmt" "github.com/tuneinsight/lattigo/v6/circuits/ckks/bootstrapping" "github.com/tuneinsight/lattigo/v6/core/rlwe" "github.com/tuneinsight/lattigo/v6/ring" "github.com/tuneinsight/lattigo/v6/schemes/ckks" "github.com/tuneinsight/lattigo/v6/utils" "github.com/tuneinsight/lattigo/v6/utils/sampling" ) func main() { LogN := 16 // Required for bootstrapping security // Residual parameters (used for actual computation) params, _ := ckks.NewParametersFromLiteral(ckks.ParametersLiteral{ LogN: LogN, LogQ: []int{55, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40}, LogP: []int{61, 61, 61}, LogDefaultScale: 40, Xs: ring.Ternary{H: 192}, // Sparse secret for security }) // Bootstrapping parameters btpParamsLit := bootstrapping.ParametersLiteral{ LogN: utils.Pointy(LogN), LogP: []int{61, 61, 61, 61}, Xs: params.Xs(), } btpParams, _ := bootstrapping.NewParametersFromLiteral(params, btpParamsLit) // Key generation kgen := rlwe.NewKeyGenerator(params) sk, pk := kgen.GenKeyPairNew() encoder := ckks.NewEncoder(params) encryptor := rlwe.NewEncryptor(params, pk) decryptor := rlwe.NewDecryptor(params, sk) // Generate bootstrapping evaluation keys (large!) fmt.Println("Generating bootstrapping keys...") evk, _, _ := btpParams.GenEvaluationKeys(sk) fmt.Println("Done") // Create bootstrapper bootstrapper, _ := bootstrapping.NewEvaluator(btpParams, evk) // Encrypt at level 0 (exhausted levels) values := make([]complex128, params.MaxSlots()) for i := range values { values[i] = sampling.RandComplex128(-1, 1) } pt := ckks.NewPlaintext(params, 0) // Level 0 encoder.Encode(values, pt) ct, _ := encryptor.EncryptNew(pt) fmt.Printf("Before bootstrap: Level %d\n", ct.Level()) // Bootstrap: refresh ciphertext to higher level ctBootstrapped, _ := bootstrapper.Bootstrap(ct) fmt.Printf("After bootstrap: Level %d\n", ctBootstrapped.Level()) // Verify correctness ptResult := decryptor.DecryptNew(ctBootstrapped) result := make([]complex128, params.MaxSlots()) encoder.Decode(ptResult, result) fmt.Printf("Precision stats: %s\n", ckks.GetPrecisionStats(params, encoder, nil, values, result, 0, false).String()) } ``` -------------------------------- ### Serialize and Deserialize Lattigo Types Source: https://context7.com/tuneinsight/lattigo/llms.txt Demonstrates how to serialize and deserialize Lattigo types like ciphertexts, parameters, and public keys to and from byte slices using Go's encoding interfaces. This is useful for network transmission and storage. ```go package main import ( "bytes" "fmt" "github.com/tuneinsight/lattigo/v6/core/rlwe" "github.com/tuneinsight/lattigo/v6/schemes/ckks" ) func main() { params, _ := ckks.NewParametersFromLiteral(ckks.ParametersLiteral{ LogN: 14, LogQ: []int{55, 45, 45, 45}, LogP: []int{61}, LogDefaultScale: 45, }) kgen := rlwe.NewKeyGenerator(params) sk := kgen.GenSecretKeyNew() pk := kgen.GenPublicKeyNew(sk) encoder := ckks.NewEncoder(params) encryptor := rlwe.NewEncryptor(params, pk) // Encrypt some data values := []float64{1.0, 2.0, 3.0, 4.0} pt := ckks.NewPlaintext(params, params.MaxLevel()) encoder.Encode(values, pt) ct, _ := encryptor.EncryptNew(pt) // Serialize ciphertext to bytes var buf bytes.Buffer ct.WriteTo(&buf) serialized := buf.Bytes() fmt.Printf("Ciphertext size: %d bytes\n", len(serialized)) // Deserialize ciphertext ctLoaded := rlwe.NewCiphertext(params, ct.Degree(), ct.Level()) ctLoaded.ReadFrom(bytes.NewReader(serialized)) // Serialize parameters paramsBytes, _ := params.MarshalBinary() fmt.Printf("Parameters size: %d bytes\n", len(paramsBytes)) // Deserialize parameters var paramsLoaded ckks.Parameters paramsLoaded.UnmarshalBinary(paramsBytes) fmt.Printf("Loaded LogN: %d\n", paramsLoaded.LogN()) // Serialize public key var pkBuf bytes.Buffer pk.WriteTo(&pkBuf) fmt.Printf("Public key size: %d bytes\n", pkBuf.Len()) } ``` -------------------------------- ### Generate Shamir Polynomial Source: https://github.com/tuneinsight/lattigo/blob/main/multiparty/README.md Generates a Shamir polynomial for threshold secret key generation. This is a prerequisite for generating Shamir secret shares. ```go poly := thresholdizer.GenShamirPolynomial() ``` -------------------------------- ### Generate Multiparty Collective Public Key Source: https://context7.com/tuneinsight/lattigo/llms.txt Enables N-out-of-N threshold cryptography where multiple parties jointly generate a public key. Decryption requires cooperation from all parties. ```go package main import ( "fmt" "github.com/tuneinsight/lattigo/v6/core/rlwe" "github.com/tuneinsight/lattigo/v6/multiparty" "github.com/tuneinsight/lattigo/v6/schemes/bgv" "github.com/tuneinsight/lattigo/v6/utils/sampling" ) func main() { params, _ := bgv.NewParametersFromLiteral(bgv.ParametersLiteral{ LogN: 14, LogQ: []int{56, 55, 55, 54, 54, 54}, LogP: []int{55, 55}, PlaintextModulus: 65537, }) N := 4 // Number of parties // Common random string for protocol crs, _ := sampling.NewKeyedPRNG([]byte{'l', 'a', 't', 't', 'i', 'g', 'o'}) // Each party generates their secret key share secretKeys := make([]*rlwe.SecretKey, N) for i := range secretKeys { secretKeys[i] = rlwe.NewKeyGenerator(params).GenSecretKeyNew() } // Collective Public Key Generation Protocol ckg := multiparty.NewPublicKeyGenProtocol(params) // Allocate shares shares := make([]multiparty.PublicKeyGenShare, N) for i := range shares { shares[i] = ckg.AllocateShare() } combined := ckg.AllocateShare() // Sample common reference polynomial crp := ckg.SampleCRP(crs) // Each party generates their share for i, sk := range secretKeys { ckg.GenShare(sk, crp, &shares[i]) } // Aggregate all shares (can be done by any party or helper) for _, share := range shares { ckg.AggregateShares(share, combined, &combined) } // Generate collective public key pk := rlwe.NewPublicKey(params) ckg.GenPublicKey(combined, crp, pk) // Now any party can encrypt using pk, but decryption requires all parties encoder := bgv.NewEncoder(params) encryptor := rlwe.NewEncryptor(params, pk) values := []uint64{1, 2, 3, 4, 5, 6, 7, 8} pt := bgv.NewPlaintext(params, params.MaxLevel()) encoder.Encode(values, pt) ct, _ := encryptor.EncryptNew(pt) fmt.Printf("Encrypted with %d-party collective key\n", N) fmt.Printf("Ciphertext level: %d\n", ct.Level()) } ``` -------------------------------- ### Aggregate Public Key Generation Shares Source: https://github.com/tuneinsight/lattigo/blob/main/multiparty/README.md Aggregates all disclosed public key generation shares. This is a necessary step before deriving the final public encryption key. ```go pkG.AggregateShares(shares) ``` -------------------------------- ### Generate Public Key Generation Share Source: https://github.com/tuneinsight/lattigo/blob/main/multiparty/README.md Generates a share for the public key generation protocol using the sampled CRP and the party's secret key. ```go share := pkG.GenShare(crp, sk) ``` -------------------------------- ### Generate Shamir Secret Share Source: https://github.com/tuneinsight/lattigo/blob/main/multiparty/README.md Generates a Shamir secret share for a specific party's public point. This share is then privately sent to that party. ```go share := thresholdizer.GenShamirSecretShare(otherPartyPublicPoint) ``` -------------------------------- ### Sample Common Random Polynomial Source: https://github.com/tuneinsight/lattigo/blob/main/multiparty/README.md Samples a common random polynomial from the Common Random String (CRS). This is used in the public key generation protocol. ```go crp := pkG.SampleCRP() ``` -------------------------------- ### Derive Public Encryption Key Source: https://github.com/tuneinsight/lattigo/blob/main/multiparty/README.md Derives the collective public encryption key from the aggregated shares. This key can then be used for encrypting messages. ```go pk := pkG.GenPublicKey() ```