From 7f03e3fc35394f2638df6032f229c48d5275986d Mon Sep 17 00:00:00 2001 From: Rolf Sommerhalder Date: Sun, 15 Feb 2026 16:00:57 +0100 Subject: [PATCH 1/8] start to upstream fork --- go/tdh2/tdh2hybridCCP/README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 go/tdh2/tdh2hybridCCP/README.md diff --git a/go/tdh2/tdh2hybridCCP/README.md b/go/tdh2/tdh2hybridCCP/README.md new file mode 100644 index 0000000..19c64fe --- /dev/null +++ b/go/tdh2/tdh2hybridCCP/README.md @@ -0,0 +1,3 @@ +## tdh2hybridCCP or tdh2hybridChaChaPoly + +This fork of /TDH2/tdh2easy provides a hybrid encryption scheme that uses Threshold Diffie-Hellman (TDH2) which is secure against adaptive chosen-ciphertext attacks (CCA2), combined with a modern symmetric stream cipher ChaCha20-Poly1305 instead of AES-256 in Galois/Counter Modem (GCM). From 08bdf0f28d832929e82d7b2bb46b898ddb61c0c4 Mon Sep 17 00:00:00 2001 From: Rolf Sommerhalder <2629503+hb9cwp@users.noreply.github.com> Date: Sun, 15 Feb 2026 19:04:18 +0100 Subject: [PATCH 2/8] Delete go/tdh2/tdh2hybridCCP/README.md --- go/tdh2/tdh2hybridCCP/README.md | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 go/tdh2/tdh2hybridCCP/README.md diff --git a/go/tdh2/tdh2hybridCCP/README.md b/go/tdh2/tdh2hybridCCP/README.md deleted file mode 100644 index 19c64fe..0000000 --- a/go/tdh2/tdh2hybridCCP/README.md +++ /dev/null @@ -1,3 +0,0 @@ -## tdh2hybridCCP or tdh2hybridChaChaPoly - -This fork of /TDH2/tdh2easy provides a hybrid encryption scheme that uses Threshold Diffie-Hellman (TDH2) which is secure against adaptive chosen-ciphertext attacks (CCA2), combined with a modern symmetric stream cipher ChaCha20-Poly1305 instead of AES-256 in Galois/Counter Modem (GCM). From 22a952496ea7af97b8eeadbe81408257ea19a4d3 Mon Sep 17 00:00:00 2001 From: Rolf Sommerhalder Date: Thu, 19 Feb 2026 11:19:46 +0100 Subject: [PATCH 3/8] initial copy from WenxingDuan's fork --- go/tdh2/tdh2easy/easy_test.go | 53 +++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 go/tdh2/tdh2easy/easy_test.go diff --git a/go/tdh2/tdh2easy/easy_test.go b/go/tdh2/tdh2easy/easy_test.go new file mode 100644 index 0000000..cc2565e --- /dev/null +++ b/go/tdh2/tdh2easy/easy_test.go @@ -0,0 +1,53 @@ +/* +Copy go/tdh2/cmd/demo/main.go from fork by WenxingDuan +https://github.com/WenxingDuan/tdh2/blob/codex/create-demo-for-threshold-encryption-and-decryption/go/tdh2/cmd/demo/main.go +and convert into a esay_test.go, similar to tdh2/tdh2hybridCCP/hybrid_test.go. +*/ + +package main + +import ( + "fmt" + + tdh2easy "github.com/smartcontractkit/tdh2/go/tdh2/tdh2easy" +) + +func main() { + // server generates keys and distributes shares to n nodes with threshold k + k, n := 3, 5 + _, pk, shares, err := tdh2easy.GenerateKeys(k, n) + if err != nil { + panic(fmt.Errorf("generate keys: %w", err)) + } + + // client encrypts a message using the public key + msg := []byte("hello threshold encryption") + ctxt, err := tdh2easy.Encrypt(pk, msg) + if err != nil { + panic(fmt.Errorf("encrypt: %w", err)) + } + + // nodes create decryption shares for the ciphertext + decShares := make([]*tdh2easy.DecryptionShare, 0, k) + for i := 0; i < k; i++ { + ds, err := tdh2easy.Decrypt(ctxt, shares[i]) + if err != nil { + panic(fmt.Errorf("decrypt share %d: %w", i, err)) + } + decShares = append(decShares, ds) + } + + // server verifies shares and combines them to recover the message + for _, s := range decShares { + if err := tdh2easy.VerifyShare(ctxt, pk, s); err != nil { + panic(fmt.Errorf("verify share: %w", err)) + } + } + recovered, err := tdh2easy.Aggregate(ctxt, decShares, n) + if err != nil { + panic(fmt.Errorf("aggregate: %w", err)) + } + + fmt.Printf("Original message: %s\n", msg) + fmt.Printf("Recovered message: %s\n", recovered) +} From 251948675911066530a966fd6655dcde0f5fca9f Mon Sep 17 00:00:00 2001 From: Rolf Sommerhalder Date: Thu, 19 Feb 2026 12:14:34 +0100 Subject: [PATCH 4/8] re-factored main.go to easy_test.go --- go/tdh2/tdh2easy/easy_test.go | 57 +++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/go/tdh2/tdh2easy/easy_test.go b/go/tdh2/tdh2easy/easy_test.go index cc2565e..918e42a 100644 --- a/go/tdh2/tdh2easy/easy_test.go +++ b/go/tdh2/tdh2easy/easy_test.go @@ -1,53 +1,66 @@ /* Copy go/tdh2/cmd/demo/main.go from fork by WenxingDuan https://github.com/WenxingDuan/tdh2/blob/codex/create-demo-for-threshold-encryption-and-decryption/go/tdh2/cmd/demo/main.go -and convert into a esay_test.go, similar to tdh2/tdh2hybridCCP/hybrid_test.go. +and convert into a esay_test.go, similar to tdh2hybridCCP/hybrid_test.go. */ - -package main +package tdh2easy import ( + "bytes" "fmt" - - tdh2easy "github.com/smartcontractkit/tdh2/go/tdh2/tdh2easy" + "testing" + //tdh2easy "github.com/smartcontractkit/tdh2/go/tdh2/tdh2easy" ) -func main() { +func TestEasy(t *testing.T) { + // Optional: Rename this to 'func main() {...}' to convert to + // a self-contained Go program. Also replace 't.' by 'log.' and + // add prefix 'tdh2easy.' to import functions & objects. + // Alternatively, rename it to 'func ExampleEasy()' or similar to test + // only for final output, see https://pkg.go.dev/testing#hdr-Examples + // server generates keys and distributes shares to n nodes with threshold k - k, n := 3, 5 - _, pk, shares, err := tdh2easy.GenerateKeys(k, n) + //k, n := 3, 5 + k, n := 7, 11 + //k, n := 99, 120 + //k, n := 121, 120 + //ms, pk, shares, err := GenerateKeys(k, n) + _, pk, shares, err := GenerateKeys(k, n) if err != nil { - panic(fmt.Errorf("generate keys: %w", err)) + t.Fatalf("Failed to generate keys: %v", err) } // client encrypts a message using the public key - msg := []byte("hello threshold encryption") - ctxt, err := tdh2easy.Encrypt(pk, msg) + msg := []byte("hybrid threshold cryptography") + ctxt, err := Encrypt(pk, msg) if err != nil { - panic(fmt.Errorf("encrypt: %w", err)) + t.Fatalf("Encryption failed: %v", err) } - // nodes create decryption shares for the ciphertext - decShares := make([]*tdh2easy.DecryptionShare, 0, k) - for i := 0; i < k; i++ { - ds, err := tdh2easy.Decrypt(ctxt, shares[i]) + // min. k of n nodes create decryption shares of the ciphertext + decShares := make([]*DecryptionShare, 0, n) // ask all n node to compute + //decShares := make([]*DecryptionShare, 0, k) // ask min. threshold k only + for i := 0; i < k; i++ { // try any shares between k and n + ds, err := Decrypt(ctxt, shares[i]) if err != nil { - panic(fmt.Errorf("decrypt share %d: %w", i, err)) + t.Fatalf("Decryption of share %d failed: %v", i, err) } decShares = append(decShares, ds) } // server verifies shares and combines them to recover the message for _, s := range decShares { - if err := tdh2easy.VerifyShare(ctxt, pk, s); err != nil { - panic(fmt.Errorf("verify share: %w", err)) + if err := VerifyShare(ctxt, pk, s); err != nil { + t.Fatalf("Verify share failed: %v", err) } } - recovered, err := tdh2easy.Aggregate(ctxt, decShares, n) + recovered, err := Aggregate(ctxt, decShares, n) if err != nil { - panic(fmt.Errorf("aggregate: %w", err)) + t.Fatalf("Aggregation of shares failed: %v", err) + } + if !bytes.Equal(recovered, msg) { + t.Fatalf("decrypeted message does not match cleartext\n got: %#v\n want: %#v", recovered, msg) } - fmt.Printf("Original message: %s\n", msg) fmt.Printf("Recovered message: %s\n", recovered) } From ec8cc90e557394d14700101e2f536bf7cbf0cb2e Mon Sep 17 00:00:00 2001 From: Rolf Sommerhalder Date: Thu, 19 Feb 2026 12:22:31 +0100 Subject: [PATCH 5/8] cleanup description --- go/tdh2/tdh2easy/easy_test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/go/tdh2/tdh2easy/easy_test.go b/go/tdh2/tdh2easy/easy_test.go index 918e42a..cd1c026 100644 --- a/go/tdh2/tdh2easy/easy_test.go +++ b/go/tdh2/tdh2easy/easy_test.go @@ -1,7 +1,7 @@ /* -Copy go/tdh2/cmd/demo/main.go from fork by WenxingDuan +Copy go/tdh2/cmd/demo/main.go from old fork by @WenxingDuan https://github.com/WenxingDuan/tdh2/blob/codex/create-demo-for-threshold-encryption-and-decryption/go/tdh2/cmd/demo/main.go -and convert into a esay_test.go, similar to tdh2hybridCCP/hybrid_test.go. +and convert into a tdh2easy/easy_test.go, similar to tdh2hybridCCP/hybrid_test.go. */ package tdh2easy @@ -9,7 +9,6 @@ import ( "bytes" "fmt" "testing" - //tdh2easy "github.com/smartcontractkit/tdh2/go/tdh2/tdh2easy" ) func TestEasy(t *testing.T) { From 8ed1a21a53dea83e4b7fef83e6a794c091be3825 Mon Sep 17 00:00:00 2001 From: Rolf Sommerhalder Date: Thu, 19 Feb 2026 12:46:00 +0100 Subject: [PATCH 6/8] add ToDo for Re-keying with Redeal() --- go/tdh2/tdh2easy/easy_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/go/tdh2/tdh2easy/easy_test.go b/go/tdh2/tdh2easy/easy_test.go index cd1c026..fa03229 100644 --- a/go/tdh2/tdh2easy/easy_test.go +++ b/go/tdh2/tdh2easy/easy_test.go @@ -2,6 +2,10 @@ Copy go/tdh2/cmd/demo/main.go from old fork by @WenxingDuan https://github.com/WenxingDuan/tdh2/blob/codex/create-demo-for-threshold-encryption-and-decryption/go/tdh2/cmd/demo/main.go and convert into a tdh2easy/easy_test.go, similar to tdh2hybridCCP/hybrid_test.go. + +ToDo: Re-key with Redeal() using Master Key (ms) and eventually different k, n. +Then repeat tests with existing & new collective Public Keys, as well as +new n individual Private Key Shares. */ package tdh2easy From 11f86b8eb985eefbe7b865d4b4b5b4bce34f530d Mon Sep 17 00:00:00 2001 From: Rolf Sommerhalder Date: Thu, 19 Feb 2026 13:16:17 +0100 Subject: [PATCH 7/8] add example how to run tests --- go/tdh2/tdh2easy/easy_test.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/go/tdh2/tdh2easy/easy_test.go b/go/tdh2/tdh2easy/easy_test.go index fa03229..ccac43b 100644 --- a/go/tdh2/tdh2easy/easy_test.go +++ b/go/tdh2/tdh2easy/easy_test.go @@ -6,6 +6,15 @@ and convert into a tdh2easy/easy_test.go, similar to tdh2hybridCCP/hybrid_test.g ToDo: Re-key with Redeal() using Master Key (ms) and eventually different k, n. Then repeat tests with existing & new collective Public Keys, as well as new n individual Private Key Shares. + +Run it together with other `*_test.go` files after change into subdir `tdh2easy` +of this repo: + +~/tdh2/go/tdh2/tdh2easy$ go test +Original message: hybrid threshold cryptography +Recovered message: hybrid threshold cryptography +PASS +ok github.com/smartcontractkit/tdh2/go/tdh2/tdh2easy 0.126s */ package tdh2easy From 42d9a5eda09b34c26757e597f0f10ef91145af7d Mon Sep 17 00:00:00 2001 From: Rolf Sommerhalder Date: Tue, 24 Feb 2026 11:57:46 +0100 Subject: [PATCH 8/8] rephrase TODO for tests after reshare --- go/tdh2/tdh2easy/easy_test.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/go/tdh2/tdh2easy/easy_test.go b/go/tdh2/tdh2easy/easy_test.go index ccac43b..4a435bb 100644 --- a/go/tdh2/tdh2easy/easy_test.go +++ b/go/tdh2/tdh2easy/easy_test.go @@ -3,8 +3,10 @@ Copy go/tdh2/cmd/demo/main.go from old fork by @WenxingDuan https://github.com/WenxingDuan/tdh2/blob/codex/create-demo-for-threshold-encryption-and-decryption/go/tdh2/cmd/demo/main.go and convert into a tdh2easy/easy_test.go, similar to tdh2hybridCCP/hybrid_test.go. -ToDo: Re-key with Redeal() using Master Key (ms) and eventually different k, n. -Then repeat tests with existing & new collective Public Keys, as well as +TODO: Rekey/"reshare" using Redeal() with the Master Key (ms), +changed threshold k and/or nodes n if desired, while keeping +the same shared Public Key that is necessary for randomness verification. +Then repeat tests with the collective Public Key, as well as new n individual Private Key Shares. Run it together with other `*_test.go` files after change into subdir `tdh2easy`