sonr/crypto/paillier/paillier.go

377 lines
9.4 KiB
Go
Raw Normal View History

feature/1114 implement account interface (#1167) - **refactor: move session-related code to middleware package** - **refactor: update PKL build process and adjust related configurations** - **feat: integrate base.cosmos.v1 Genesis module** - **refactor: pass session context to modal rendering functions** - **refactor: move nebula package to app directory and update templ version** - **refactor: Move home section video view to dedicated directory** - **refactor: remove unused views file** - **refactor: move styles and UI components to global scope** - **refactor: Rename images.go to cdn.go** - **feat: Add Empty State Illustrations** - **refactor: Consolidate Vault Index Logic** - **fix: References to App.wasm and remove Vault Directory embedded CDN files** - **refactor: Move CDN types to Models** - **fix: Correct line numbers in templ error messages for arch_templ.go** - **refactor: use common types for peer roles** - **refactor: move common types and ORM to a shared package** - **fix: Config import dwn** - **refactor: move nebula directory to app** - **feat: Rebuild nebula** - **fix: correct file paths in panels templates** - **feat: Remove duplicate types** - **refactor: Move dwn to pkg/core** - **refactor: Binary Structure** - **feat: Introduce Crypto Pkg** - **fix: Broken Process Start** - **feat: Update pkg/* structure** - **feat: Refactor PKL Structure** - **build: update pkl build process** - **chore: Remove Empty Files** - **refactor: remove unused macaroon package** - **feat: Add WebAwesome Components** - **refactor: consolidate build and generation tasks into a single taskfile, remove redundant makefile targets** - **refactor: refactor server and move components to pkg/core/dwn** - **build: update go modules** - **refactor: move gateway logic into dedicated hway command** - **feat: Add KSS (Krawczyk-Song-Song) MPC cryptography module** - **feat: Implement MPC-based JWT signing and UCAN token generation** - **feat: add support for MPC-based JWT signing** - **feat: Implement MPC-based UCAN capabilities for smart accounts** - **feat: add address field to keyshareSource** - **feat: Add comprehensive MPC test suite for keyshares, UCAN tokens, and token attenuations** - **refactor: improve MPC keyshare management and signing process** - **feat: enhance MPC capability hierarchy documentation** - **refactor: rename GenerateKeyshares function to NewKeyshareSource for clarity** - **refactor: remove unused Ethereum address computation** - **feat: Add HasHandle and IsAuthenticated methods to HTTPContext** - **refactor: Add context.Context support to session HTTPContext** - **refactor: Resolve context interface conflicts in HTTPContext** - **feat: Add session ID context key and helper functions** - **feat: Update WebApp Page Rendering** - **refactor: Simplify context management by using single HTTPContext key** - **refactor: Simplify HTTPContext creation and context management in session middleware** - **refactor: refactor session middleware to use a single data structure** - **refactor: Simplify HTTPContext implementation and session data handling** - **refactor: Improve session context handling and prevent nil pointer errors** - **refactor: Improve session context handling with nil safety and type support** - **refactor: improve session data injection** - **feat: add full-screen modal component and update registration flow** - **chore: add .air.toml to .gitignore** - **feat: add Air to devbox and update dependencies**
2024-11-23 01:28:58 -05:00
//
// Copyright Coinbase, Inc. All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//
// Package paillier contains Paillier's cryptosystem (1999) [P99].
// Public-Key Cryptosystems Based on Composite Degree Residuosity Class.
// http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.112.4035&rep=rep1&type=pdf
// All routines here from pseudocode §2.5. Fig 1: The Paillier Cryptosystem.
//
// This module provides APIs for:
//
// - generating a safe keypair,
// - encryption and decryption,
// - adding two encrypted values, Enc(a) and Enc(b), and obtaining Enc(a + b), and
// - multiplying a plain value, a, and an encrypted value Enc(b), and obtaining Enc(a * b).
//
// The encrypted values are represented as big.Int and are serializable. This module also provides
// JSON serialization for the PublicKey and the SecretKey.
package paillier
import (
"encoding/json"
"fmt"
"math/big"
"github.com/pkg/errors"
feature/1121 implement ucan validation (#1176) - **refactor: remove unused auth components** - **refactor: improve devbox configuration and deployment process** - **refactor: improve devnet and testnet setup** - **fix: update templ version to v0.2.778** - **refactor: rename pkl/net.matrix to pkl/matrix.net** - **refactor: migrate webapp components to nebula** - **refactor: protobuf types** - **chore: update dependencies for improved security and stability** - **feat: implement landing page and vault gateway servers** - **refactor: Migrate data models to new module structure and update related files** - **feature/1121-implement-ucan-validation** - **refactor: Replace hardcoded constants with model types in attns.go** - **feature/1121-implement-ucan-validation** - **chore: add origin Host struct and update main function to handle multiple hosts** - **build: remove unused static files from dwn module** - **build: remove unused static files from dwn module** - **refactor: Move DWN models to common package** - **refactor: move models to pkg/common** - **refactor: move vault web app assets to embed module** - **refactor: update session middleware import path** - **chore: configure port labels and auto-forwarding behavior** - **feat: enhance devcontainer configuration** - **feat: Add UCAN middleware for Echo with flexible token validation** - **feat: add JWT middleware for UCAN authentication** - **refactor: update package URI and versioning in PklProject files** - **fix: correct sonr.pkl import path** - **refactor: move JWT related code to auth package** - **feat: introduce vault configuration retrieval and management** - **refactor: Move vault components to gateway module and update file paths** - **refactor: remove Dexie and SQLite database implementations** - **feat: enhance frontend with PWA features and WASM integration** - **feat: add Devbox features and streamline Dockerfile** - **chore: update dependencies to include TigerBeetle** - **chore(deps): update go version to 1.23** - **feat: enhance devnet setup with PATH environment variable and updated PWA manifest** - **fix: upgrade tigerbeetle-go dependency and remove indirect dependency** - **feat: add PostgreSQL support to devnet and testnet deployments** - **refactor: rename keyshare cookie to token cookie** - **feat: upgrade Go version to 1.23.3 and update dependencies** - **refactor: update devnet and testnet configurations** - **feat: add IPFS configuration for devnet** - **I'll help you update the ipfs.config.pkl to include all the peers from the shell script. Here's the updated configuration:** - **refactor: move mpc package to crypto directory** - **feat: add BIP32 support for various cryptocurrencies** - **feat: enhance ATN.pkl with additional capabilities** - **refactor: simplify smart account and vault attenuation creation** - **feat: add new capabilities to the Attenuation type** - **refactor: Rename MPC files for clarity and consistency** - **feat: add DIDKey support for cryptographic operations** - **feat: add devnet and testnet deployment configurations** - **fix: correct key derivation in bip32 package** - **refactor: rename crypto/bip32 package to crypto/accaddr** - **fix: remove duplicate indirect dependency** - **refactor: move vault package to root directory** - **refactor: update routes for gateway and vault** - **refactor: remove obsolete web configuration file** - **refactor: remove unused TigerBeetle imports and update host configuration** - **refactor: adjust styles directory path** - **feat: add broadcastTx and simulateTx functions to gateway** - **feat: add PinVault handler**
2024-12-02 14:27:18 -05:00
"github.com/onsonr/sonr/crypto/core"
"github.com/onsonr/sonr/crypto/internal"
feature/1114 implement account interface (#1167) - **refactor: move session-related code to middleware package** - **refactor: update PKL build process and adjust related configurations** - **feat: integrate base.cosmos.v1 Genesis module** - **refactor: pass session context to modal rendering functions** - **refactor: move nebula package to app directory and update templ version** - **refactor: Move home section video view to dedicated directory** - **refactor: remove unused views file** - **refactor: move styles and UI components to global scope** - **refactor: Rename images.go to cdn.go** - **feat: Add Empty State Illustrations** - **refactor: Consolidate Vault Index Logic** - **fix: References to App.wasm and remove Vault Directory embedded CDN files** - **refactor: Move CDN types to Models** - **fix: Correct line numbers in templ error messages for arch_templ.go** - **refactor: use common types for peer roles** - **refactor: move common types and ORM to a shared package** - **fix: Config import dwn** - **refactor: move nebula directory to app** - **feat: Rebuild nebula** - **fix: correct file paths in panels templates** - **feat: Remove duplicate types** - **refactor: Move dwn to pkg/core** - **refactor: Binary Structure** - **feat: Introduce Crypto Pkg** - **fix: Broken Process Start** - **feat: Update pkg/* structure** - **feat: Refactor PKL Structure** - **build: update pkl build process** - **chore: Remove Empty Files** - **refactor: remove unused macaroon package** - **feat: Add WebAwesome Components** - **refactor: consolidate build and generation tasks into a single taskfile, remove redundant makefile targets** - **refactor: refactor server and move components to pkg/core/dwn** - **build: update go modules** - **refactor: move gateway logic into dedicated hway command** - **feat: Add KSS (Krawczyk-Song-Song) MPC cryptography module** - **feat: Implement MPC-based JWT signing and UCAN token generation** - **feat: add support for MPC-based JWT signing** - **feat: Implement MPC-based UCAN capabilities for smart accounts** - **feat: add address field to keyshareSource** - **feat: Add comprehensive MPC test suite for keyshares, UCAN tokens, and token attenuations** - **refactor: improve MPC keyshare management and signing process** - **feat: enhance MPC capability hierarchy documentation** - **refactor: rename GenerateKeyshares function to NewKeyshareSource for clarity** - **refactor: remove unused Ethereum address computation** - **feat: Add HasHandle and IsAuthenticated methods to HTTPContext** - **refactor: Add context.Context support to session HTTPContext** - **refactor: Resolve context interface conflicts in HTTPContext** - **feat: Add session ID context key and helper functions** - **feat: Update WebApp Page Rendering** - **refactor: Simplify context management by using single HTTPContext key** - **refactor: Simplify HTTPContext creation and context management in session middleware** - **refactor: refactor session middleware to use a single data structure** - **refactor: Simplify HTTPContext implementation and session data handling** - **refactor: Improve session context handling and prevent nil pointer errors** - **refactor: Improve session context handling with nil safety and type support** - **refactor: improve session data injection** - **feat: add full-screen modal component and update registration flow** - **chore: add .air.toml to .gitignore** - **feat: add Air to devbox and update dependencies**
2024-11-23 01:28:58 -05:00
)
// PaillierPrimeBits is the number of bits used to generate Paillier Safe Primes.
const PaillierPrimeBits = 1024
type (
// PublicKey is a Paillier public key: N = P*Q; for safe primes P,Q.
PublicKey struct {
N *big.Int // N = PQ
N2 *big.Int // N² computed and cached to prevent re-computation.
}
// PublicKeyJson encapsulates the data that is serialized to JSON.
// It is used internally and not for external use. Public so other pieces
// can use for serialization.
PublicKeyJson struct {
N *big.Int
}
// SecretKey is a Paillier secret key.
SecretKey struct {
PublicKey
Lambda *big.Int // lcm(P - 1, Q - 1)
Totient *big.Int // Euler's totient: (P - 1) * (Q - 1)
U *big.Int // L((N + 1)^λ(N) mod N²)1 mod N
}
// SecretKeyJson encapsulates the data that is serialized to JSON.
// It is used internally and not for external use. Public so other pieces
// can use for serialization.
SecretKeyJson struct {
N, Lambda, Totient, U *big.Int
}
// Ciphertext in Pailler's cryptosystem: a value $c \in Z_{N²}$ .
Ciphertext *big.Int
)
var two = big.NewInt(2) // The odd prime
// NewKeys generates Paillier keys with `bits` sized safe primes.
func NewKeys() (*PublicKey, *SecretKey, error) {
return keyGenerator(core.GenerateSafePrime, PaillierPrimeBits)
}
// keyGenerator generates Paillier keys with `bits` sized safe primes using function
// `genSafePrime` to generate the safe primes.
func keyGenerator(genSafePrime func(uint) (*big.Int, error), bits uint) (*PublicKey, *SecretKey, error) {
values := make(chan *big.Int, 2)
errors := make(chan error, 2)
var p, q *big.Int
for p == q {
for range []int{1, 2} {
go func() {
value, err := genSafePrime(bits)
values <- value
errors <- err
}()
}
for _, err := range []error{<-errors, <-errors} {
if err != nil {
return nil, nil, err
}
}
p, q = <-values, <-values
}
// Assemble the secret/public key pair.
sk, err := NewSecretKey(p, q)
if err != nil {
return nil, nil, err
}
return &sk.PublicKey, sk, nil
}
// NewSecretKey computes intermediate values based on safe primes p, q.
func NewSecretKey(p, q *big.Int) (*SecretKey, error) {
if p == nil || q == nil {
return nil, internal.ErrNilArguments
}
// Pre-compute necessary values.
pm1 := new(big.Int).Sub(p, core.One) // P - 1
qm1 := new(big.Int).Sub(q, core.One) // Q - 1
n := new(big.Int).Mul(p, q) // N = PQ
nn := new(big.Int).Mul(n, n) // N²
lambda, err := lcm(pm1, qm1) // λ(N) = lcm(P-1, Q-1)
if err != nil {
// Code coverage note: lcm returns error only if the inputs are nil, which can never happen here.
return nil, err
}
totient := new(big.Int).Mul(pm1, qm1) // 𝝋(N) = (P-1)(Q-1)
pk := PublicKey{
N: n,
N2: nn,
}
// (N+1)^λ(N) mod N²
t := new(big.Int).Add(n, core.One)
t.Exp(t, lambda, nn)
// L((N+1)^λ(N) mod N²)
u, err := pk.l(t)
if err != nil {
return nil, err
}
// L((N+1)^λ(N) mod N²)^-1 mod N
u.ModInverse(u, n)
return &SecretKey{pk, lambda, totient, u}, nil
}
// MarshalJSON converts the public key into json format.
func (pk PublicKey) MarshalJSON() ([]byte, error) {
data := PublicKeyJson{pk.N}
return json.Marshal(data)
}
// UnmarshalJSON converts the json data into this public key.
func (pk *PublicKey) UnmarshalJSON(bytes []byte) error {
data := new(PublicKeyJson)
if err := json.Unmarshal(bytes, data); err != nil {
return err
}
if data.N == nil {
return nil
}
pk.N = data.N
pk.N2 = new(big.Int).Mul(data.N, data.N)
return nil
}
// lcm calculates the least common multiple.
func lcm(x, y *big.Int) (*big.Int, error) {
if x == nil || y == nil {
return nil, internal.ErrNilArguments
}
gcd := new(big.Int).GCD(nil, nil, x, y)
if core.ConstantTimeEq(gcd, core.Zero) {
return core.Zero, nil
}
// Compute least common multiple: https://en.wikipedia.org/wiki/Least_common_multiple#Calculation .
b := new(big.Int)
return b.Abs(b.Mul(b.Div(x, gcd), y)), nil
}
// l computes a residuosity class of n^2: (x - 1) / n.
// Where it is the quotient x - 1 divided by n not modular multiplication of x - 1 times
// the modular multiplicative inverse of n. The function name comes from [P99].
func (pk *PublicKey) l(x *big.Int) (*big.Int, error) {
if x == nil {
return nil, internal.ErrNilArguments
}
if core.ConstantTimeEq(pk.N, core.Zero) {
return nil, internal.ErrNCannotBeZero
}
// Ensure x = 1 mod N
if !core.ConstantTimeEq(new(big.Int).Mod(x, pk.N), core.One) {
return nil, internal.ErrResidueOne
}
// Ensure x ∈ Z_N²
if err := core.In(x, pk.N2); err != nil {
return nil, err
}
// (x - 1) / n
b := new(big.Int).Sub(x, core.One)
return b.Div(b, pk.N), nil
}
// NewPubkey initializes a Paillier public key with a given n.
func NewPubkey(n *big.Int) (*PublicKey, error) {
if n == nil {
return nil, errors.New("n cannot be nil")
}
return &PublicKey{
N: n,
N2: new(big.Int).Mul(n, n), // Compute and cache N²
}, nil
}
// Add combines two Paillier ciphertexts.
func (pk *PublicKey) Add(c, d Ciphertext) (Ciphertext, error) {
if c == nil || d == nil {
return nil, internal.ErrNilArguments
}
// Ensure c,d ∈ Z_N²
cErr := core.In(c, pk.N2)
dErr := core.In(d, pk.N2)
// Constant time error check
var err error
if cErr != nil {
err = cErr
}
if dErr != nil {
err = dErr
}
if err != nil {
return nil, err
}
ctxt, err := core.Mul(c, d, pk.N2)
if err != nil {
// Code coverage note: core.Mul returns error only if the inputs are nil, which can never happen here.
return nil, err
}
return ctxt, nil
}
// Mul is equivalent to adding two Paillier exponents.
func (pk *PublicKey) Mul(a *big.Int, c Ciphertext) (Ciphertext, error) {
if a == nil || c == nil {
return nil, internal.ErrNilArguments
}
// Ensure a ∈ Z_N
aErr := core.In(a, pk.N)
// Ensure c ∈ Z_N²
cErr := core.In(c, pk.N2)
var err error
// Constant time error check
if aErr != nil {
err = aErr
}
if cErr != nil {
err = cErr
}
if err != nil {
return nil, err
}
return new(big.Int).Exp(c, a, pk.N2), nil
}
// Encrypt produces a ciphertext on input message.
func (pk *PublicKey) Encrypt(msg *big.Int) (Ciphertext, *big.Int, error) {
// generate a nonce: r \in Z**_N
r, err := core.Rand(pk.N)
if err != nil {
return nil, nil, err
}
// Generate and return the ciphertext
ct, err := pk.encrypt(msg, r)
return ct, r, err
}
// encrypt produces a ciphertext on input a message and nonce.
func (pk *PublicKey) encrypt(msg, r *big.Int) (Ciphertext, error) {
if msg == nil || r == nil {
return nil, internal.ErrNilArguments
}
// Ensure msg ∈ Z_N
if err := core.In(msg, pk.N); err != nil {
return nil, err
}
// Ensure r ∈ Z^*_N: we use the method proved in docs/[EL20]
// ensure r ∈ Z^_N-{0}
if err := core.In(r, pk.N); err != nil {
return nil, err
}
if core.ConstantTimeEq(r, core.Zero) {
return nil, fmt.Errorf("r cannot be 0")
}
// Compute the ciphertext components: ɑ, β
// ɑ = (N+1)^m (mod N²)
ɑ := new(big.Int).Add(pk.N, core.One)
ɑ.Exp(ɑ, msg, pk.N2)
β := new(big.Int).Exp(r, pk.N, pk.N2) // β = r^N (mod N²)
// ciphertext = ɑ*β = (N+1)^m * r^N (mod N²)
c, err := core.Mul(ɑ, β, pk.N2)
if err != nil {
// Code coverage note: core.Mul returns error only if the inputs are nil, which can never happen here.
return nil, err
}
return c, nil
}
// Decrypt is the reverse operation of Encrypt.
func (sk *SecretKey) Decrypt(c Ciphertext) (*big.Int, error) {
if c == nil {
return nil, internal.ErrNilArguments
}
// Ensure C ∈ Z_N²
if err := core.In(c, sk.N2); err != nil {
return nil, err
}
// Compute the msg in components
// ɑ ≡ c^{λ(N)} mod N²
ɑ := new(big.Int).Exp(c, sk.Lambda, sk.N2)
// l = L(ɑ, N)
ell, err := sk.l(ɑ)
if err != nil {
return nil, err
}
// Compute the msg
// m ≡ lu = L(ɑ)*u = L(c^{λ(N)})*u mod N
m, err := core.Mul(ell, sk.U, sk.N)
if err != nil {
return nil, err
}
return m, nil
}
// MarshalJSON converts the secret key into json format.
func (sk SecretKey) MarshalJSON() ([]byte, error) {
data := SecretKeyJson{
sk.N,
sk.Lambda,
sk.Totient,
sk.U,
}
return json.Marshal(data)
}
// UnmarshalJSON converts the json data into this secret key.
func (sk *SecretKey) UnmarshalJSON(bytes []byte) error {
data := new(SecretKeyJson)
if err := json.Unmarshal(bytes, data); err != nil {
return err
}
if data.N != nil {
sk.N = data.N
sk.N2 = new(big.Int).Mul(data.N, data.N)
}
sk.U = data.U
sk.Totient = data.Totient
sk.Lambda = data.Lambda
return nil
}