mirror of
https://github.com/sonr-io/crypto.git
synced 2026-08-02 15:31:38 +00:00
No commit suggestions generated
This commit is contained in:
Executable
+23
@@ -0,0 +1,23 @@
|
||||
---
|
||||
aliases: [README]
|
||||
tags: []
|
||||
title: README
|
||||
linter-yaml-title-alias: README
|
||||
date created: Wednesday, April 17th 2024, 4:11:40 pm
|
||||
date modified: Thursday, April 18th 2024, 8:19:25 am
|
||||
---
|
||||
|
||||
## Paillier Cryptosystem
|
||||
|
||||
Package paillier contains [Paillier's cryptosystem (1999)](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 key pair
|
||||
- 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.
|
||||
@@ -0,0 +1,377 @@
|
||||
//
|
||||
// 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"
|
||||
|
||||
"github.com/sonr-io/sonr/crypto/core"
|
||||
"github.com/sonr-io/sonr/crypto/internal"
|
||||
)
|
||||
|
||||
// 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
|
||||
)
|
||||
|
||||
// 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
|
||||
}
|
||||
+235
@@ -0,0 +1,235 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// This file contains proofs that Paillier moduli are square-free: [spec] fig 15
|
||||
|
||||
package paillier
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
crypto "github.com/sonr-io/sonr/crypto/core"
|
||||
"github.com/sonr-io/sonr/crypto/core/curves"
|
||||
"github.com/sonr-io/sonr/crypto/internal"
|
||||
)
|
||||
|
||||
// [spec] 10.2 and ProvePSF, VerifyPSF fig.15
|
||||
const PsfProofLength = 13
|
||||
|
||||
// PsfProofParams contains the inputs to ProvePSF
|
||||
type PsfProofParams struct {
|
||||
Curve elliptic.Curve
|
||||
SecretKey *SecretKey
|
||||
Pi uint32
|
||||
Y *curves.EcPoint
|
||||
}
|
||||
|
||||
// PsfVerifyParams contains the inputs to VerifyPSF
|
||||
type PsfVerifyParams struct {
|
||||
Curve elliptic.Curve
|
||||
PublicKey *PublicKey
|
||||
Pi uint32
|
||||
Y *curves.EcPoint
|
||||
}
|
||||
|
||||
// PsfProof is a slice of 13 big.Int's that prove that a Paillier modulus is square-free
|
||||
type PsfProof []*big.Int
|
||||
|
||||
// Prove that a Paillier modulus is square-free
|
||||
// [spec] §10.fig 15
|
||||
func (p *PsfProofParams) Prove() (PsfProof, error) {
|
||||
// Verify that params are sane
|
||||
if p.Curve == nil ||
|
||||
p.SecretKey == nil ||
|
||||
p.Pi == 0 ||
|
||||
p.Y == nil {
|
||||
return nil, internal.ErrNilArguments
|
||||
}
|
||||
|
||||
// 1. ell = 13
|
||||
// Note this is set above as PsfProofLength
|
||||
|
||||
// 2. M = N^{-1} mod \phi(N)
|
||||
M, err := crypto.Inv(p.SecretKey.N, p.SecretKey.Totient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 3. [x_1, ..., x_ell] <- GenerateChallenges(g,q,y,Pi,ell)
|
||||
// NOTE: spec doesn't include N, but it's an oversight--should be part of the
|
||||
// commitment
|
||||
x, err := generateChallenges(p.Curve.Params(), p.SecretKey.N, p.Pi, p.Y)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(x) != PsfProofLength {
|
||||
return nil, fmt.Errorf(
|
||||
"challenges array is not correct length: want=%v got=%v",
|
||||
PsfProofLength,
|
||||
len(x),
|
||||
)
|
||||
}
|
||||
|
||||
// 4. For i = [1, ... \ell]
|
||||
// NOTE: typo in spec: says j = ... but uses subscript i in loop
|
||||
proof := make([]*big.Int, PsfProofLength)
|
||||
for i, xj := range x {
|
||||
// 5. Compute y_i = x_i^M mod N
|
||||
// NOTE: the pseudocode shows mod phi(N) which is incorrect
|
||||
// it should be mod N otherwise the reverse in Verify
|
||||
// will fail. Using phi(N) puts M in the wrong group.
|
||||
yi, err := crypto.Exp(xj, M, p.SecretKey.N)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 6. Set \Pi = [y_1, ..., y_\ell]
|
||||
// NOTE: typo in spec: says y_t not y_\ell
|
||||
proof[i] = yi
|
||||
}
|
||||
|
||||
// 7. return \Pi
|
||||
return proof, nil
|
||||
}
|
||||
|
||||
// Verify that a Paillier modulus is square-free
|
||||
// [spec] §10.fig 15
|
||||
func (p PsfProof) Verify(psf *PsfVerifyParams) error {
|
||||
// Verify that params are sane
|
||||
if psf == nil ||
|
||||
psf.Curve == nil ||
|
||||
psf.PublicKey == nil ||
|
||||
psf.Pi == 0 ||
|
||||
psf.Y == nil {
|
||||
return internal.ErrNilArguments
|
||||
}
|
||||
|
||||
// 1. ell = 13
|
||||
// Note this is set above as PsfProofLength
|
||||
|
||||
// 2. t = 1000
|
||||
// NOTE not used anywhere
|
||||
|
||||
// 3. if q|N return false
|
||||
if new(big.Int).Mod(psf.PublicKey.N, psf.Curve.Params().N).Cmp(crypto.Zero) == 0 {
|
||||
return fmt.Errorf("paillier public key is a multiple of the curve subgroup")
|
||||
}
|
||||
|
||||
// 4. [x_1, ..., x_ell] <- GenerateChallenges(g,q,y,Pi,ell)
|
||||
// NOTE: spec doesn't include N, but it's an oversight--should be part of the
|
||||
// commitment
|
||||
x, err := generateChallenges(psf.Curve.Params(), psf.PublicKey.N, psf.Pi, psf.Y)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(x) != PsfProofLength {
|
||||
return fmt.Errorf(
|
||||
"challenges array is not correct length: want=%v got=%v",
|
||||
PsfProofLength,
|
||||
len(x),
|
||||
)
|
||||
}
|
||||
|
||||
// 5. for j in [1,...,l]
|
||||
for j, xj := range x {
|
||||
// 6. yj^N != x mod N return false
|
||||
// NOTE: pseudocode uses i when loop uses j
|
||||
lhs, err := crypto.Exp(p[j], psf.PublicKey.N, psf.PublicKey.N)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if lhs.Cmp(xj) != 0 {
|
||||
return fmt.Errorf("not equal at %d", j)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// generateChallenges computes `l` deterministic numbers as
|
||||
// challenges for PsfProof which proves that the Paillier modulus is square free
|
||||
// [spec] fig.15 GenerateChallenges
|
||||
func generateChallenges(
|
||||
params *elliptic.CurveParams,
|
||||
N *big.Int,
|
||||
pi uint32,
|
||||
y *curves.EcPoint,
|
||||
) ([]*big.Int, error) {
|
||||
if params == nil ||
|
||||
y == nil ||
|
||||
pi == 0 {
|
||||
return nil, internal.ErrNilArguments
|
||||
}
|
||||
|
||||
// 1. Set b = |N| // bit length of N
|
||||
b := N.BitLen()
|
||||
|
||||
// a modulus that is too small turns this function into an infinite loop
|
||||
// need at least a byte to guarantee termination
|
||||
if b < 8 {
|
||||
return nil, internal.ErrNilArguments
|
||||
}
|
||||
|
||||
// 2. h = output bit-length of fiat-shamir hash
|
||||
// See util.fiatShamir which uses sha256
|
||||
// So the output bit-length is 256 bits
|
||||
const h int = 256
|
||||
|
||||
// 3. Compute s = ⌈b/h⌉ // number of hash outputs required to obtain b bits
|
||||
// i.e. the number of times we have to call fs-shamir to get the same bits as
|
||||
// `b`. Compute ceil as ceilVal = (a+b-1) / b
|
||||
s := int64((b + h - 1) / h)
|
||||
|
||||
// 4. j = 0
|
||||
j := int64(0)
|
||||
|
||||
// 5. m = 0
|
||||
m := big.NewInt(0)
|
||||
|
||||
x := make([]*big.Int, PsfProofLength)
|
||||
|
||||
Pi := new(big.Int).SetUint64(uint64(pi))
|
||||
// 6. while j ≤ l
|
||||
for j < PsfProofLength {
|
||||
|
||||
bij := big.NewInt(j)
|
||||
var ej []byte
|
||||
|
||||
// 7. for k = [1,...,s]
|
||||
for k := int64(1); k <= s; k++ {
|
||||
bik := big.NewInt(k)
|
||||
|
||||
// 8. Compute e_jk = FS-HASH(g, q, y, p_i, j, k, m)
|
||||
res, err := crypto.FiatShamir(params.Gx, params.Gy, params.N, y.X, y.Y, Pi, bij, bik, m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 9. Set x_j = eJ1 || ... || eJs
|
||||
// Pseudocode says to concatenate outside this loop
|
||||
// however, we just concatenate the bytes now instead of storing as temporary
|
||||
// variables
|
||||
ej = append(ej, res...)
|
||||
}
|
||||
// 10. Truncate ej to b bits
|
||||
xj := new(big.Int).SetBytes(ej[:b/8])
|
||||
|
||||
// 11. if x_j < Z_N* i.e. 0 < x_j and x_j < N
|
||||
if xj.Cmp(crypto.Zero) == 1 && xj.Cmp(N) == -1 {
|
||||
x[j] = xj
|
||||
|
||||
// 12 j = j + 1
|
||||
j++
|
||||
// 13 m = 0
|
||||
m = big.NewInt(0)
|
||||
// 14 else
|
||||
} else {
|
||||
// 15. Set m = m + 1
|
||||
m.Add(m, crypto.One)
|
||||
}
|
||||
}
|
||||
return x, nil
|
||||
}
|
||||
@@ -0,0 +1,394 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package paillier
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
crypto "github.com/sonr-io/sonr/crypto/core"
|
||||
curves2 "github.com/sonr-io/sonr/crypto/core/curves"
|
||||
"github.com/sonr-io/sonr/crypto/internal"
|
||||
)
|
||||
|
||||
var testPrimes = []*big.Int{
|
||||
internal.B10(
|
||||
"186141419611617071752010179586510154515933389116254425631491755419216243670159714804545944298892950871169229878325987039840135057969555324774918895952900547869933648175107076399993833724447909579697857041081987997463765989497319509683575289675966710007879762972723174353568113668226442698275449371212397561567",
|
||||
),
|
||||
internal.B10(
|
||||
"94210786053667323206442523040419729883258172350738703980637961803118626748668924192069593010365236618255120977661397310932923345291377692570649198560048403943687994859423283474169530971418656709749020402756179383990602363122039939937953514870699284906666247063852187255623958659551404494107714695311474384687",
|
||||
),
|
||||
internal.B10(
|
||||
"130291226847076770981564372061529572170236135412763130013877155698259035960569046218348763182598589633420963942796327547969527085797839549642610021986391589746295634536750785366034581957858065740296991986002552598751827526181747791647357767502200771965093659353354985289411489453223546075843993686648576029043",
|
||||
),
|
||||
internal.B10(
|
||||
"172938910323633442195852028319756134734590277522945546987913328782597284762767185925315797321999389252040294991952361905020940252121762387957669654615602135429944435719699091344247805645764550860505536884031064967454028383404046221898300153428182409080298694828920944094158777327533157774919783417586902830043",
|
||||
),
|
||||
internal.B10(
|
||||
"135841191929788643010555393808775051922265083622266098277752143441294911675705272940799534437169053045878247274810449617960047255023823301284034559807472662111224710158898548617194658983006262996831617082584649612602010680423107108651221824216065228161009680618243402116924511141821829055830713600437589058643",
|
||||
),
|
||||
internal.B10(
|
||||
"179677777376220950493907657233669314916823596507009854134559513388779535023958212632715646194917807302098015450071151245496651913873851032302340489007561121851068326577148680474495447007833318066335149850926605897908761267606415610900931306044455332084757793630487163583451178807470499389106913845684353833379",
|
||||
),
|
||||
internal.B10(
|
||||
"62649985409697862206708027961094957171873130708493280862148817115812710388878279240372941307490519941098268192630359164091992515623574326498710952492586770923230983753287493884398990474917756375654842939939940915963324175552421981212594421823752854754541693709434365609636589761589816398869727328798680335583",
|
||||
),
|
||||
internal.B10(
|
||||
"196576931859098680370388202020086631604584490828609819764890020064880575503817891126703473215983239396058738287255240835101797315137072822716923594188151190460588551553676484461393180135097616711975997391550414447010491794087888246885960280296709672609456539741162207414899687167396008233995214434586323322859",
|
||||
),
|
||||
internal.B10(
|
||||
"271336420864746369701165973306090650688066226258594853124089876839120277465060891854507381090238664515950686049792387028144049076707224579184820539700879884119579186284072404459682082855184644444282438298561112002507411996589407330801765394106772460665497195944412067027079123717579308322520985921886949051399",
|
||||
),
|
||||
internal.B10(
|
||||
"147653127360336844448178027222853805809444645720500374788954343695331927468524513989671450440433430392339037667457657655958027740671071573403925974795764987870476118984896439440386146680643457835633462311776946902713168513155240275028008685964121441954481847113848701823211862974120297600518927026940189810103",
|
||||
),
|
||||
internal.B10(
|
||||
"61539010433774119199101441060312213379096965116494840834113311373246794436251480454630309900106802555812462300777026043563820643373439814989443964169335227347638731691284339678436222951965582264570176875078394338903074717434072995072121221264531723385013005031614327462206339323414428493321384497439106152163",
|
||||
),
|
||||
internal.B10(
|
||||
"311771090987243597109711542316907830756641693311804000593662622484722315782429237915515708860530841821213561483232298821623675096481796856960171671330638042763441430256097782130268494276848432981045602236986861083392706904041234926428759947857376161689191720483868111001987710383245853931937989224732484206639",
|
||||
),
|
||||
internal.B10(
|
||||
"348545239501897032367950520763624245702184225360238826931782856428685149253861325854706825698843098817604431561258712026020688621010635185480321876001016614912927680387840531641703966894322797491484955817022624047355473480912508041252361257911175397626575812830091471419378132244146077774966527307225203863239",
|
||||
),
|
||||
internal.B10(
|
||||
"167562983031509383478485987630533113343120902430985961468758712448125734458812918541051012669749885569679178971612428577288632429606851871845164719448590160530844833425628143996971699662729056519326776907622035340086832629206691942750594912221135787534670122007438859975313187460872690748138136170080913902203",
|
||||
),
|
||||
internal.B10(
|
||||
"151715609132228776595716500435665208768897792993205818803431003524953811539898459230192282642811956896879836518212758893685104146944932088195466999437630114129887975508715417094019351746027667352287673763064246395392591213231796089814648654152625331299642171758052545451706130433176935280325874961374276589763",
|
||||
),
|
||||
internal.B10(
|
||||
"281712498774102170277967098381151873986368736986748325672760355775943894718315925237789122870763991635031524237638254080973752419302437870447849091185409669906909828874532209010547976564209374430136988588219470076527433259993640332285914706329187116209118972038509278879237122949265824264856530096167843589043",
|
||||
),
|
||||
internal.B10(
|
||||
"86882427063713590116032012033991745733440719961931885774819345297872782432110706546175706398857226544896860987721577779470479838062106788873559026307646871133570915480684987993282364698928926188640576189281202695899665555602891606955025957497645420156315890379148794822782242384167644977894987285630058930123",
|
||||
),
|
||||
internal.B10(
|
||||
"83303406464212917441403726886711948278716398972782717472384580707071541544369912289531948826578557956123897261910116726555850408667234850301141318443154703778225305104540324875867615851047711871915209458107086347063530255813116254895432804373554367035028329996279513893337862177371103671113527972705508417219",
|
||||
),
|
||||
internal.B10(
|
||||
"290829612093510969863838578444630131194824970528125429399090307997156531200557462531776190769158191441614466855963164356672434851525764502180873524299787560160992955274777477308009367164212073773611071813219472273292916120276721541591451163160398750751633065097434700462944540404208636130411713202759646572187",
|
||||
),
|
||||
internal.B10(
|
||||
"48881643615473281990659967689574873112454227417010573158578046287415357392674453353386274403945930212163960526780980360358370255117866064326375672959460785974850231208253282115124348836379470403659096433419030132737534978624170609788431758477453270578400762995584298785082853409573009591146163658067217132999",
|
||||
),
|
||||
internal.B10(
|
||||
"47818664065019136841944639898604168570191742429107462510943153778085167306149797958497736138014922106778177497683417470713996340979203175236987691632152128071256018368891463388744514315997309312144264057334961479235114340091423812710466596081259537323405527816634204224641066174554915788023121121924554823463",
|
||||
),
|
||||
internal.B10(
|
||||
"229695065817346126758526483359337260282925372883465036895664320607569899180246065431164369223444026964554195802821338287119074827091354255558249504915527499047398698041873875019622138440848556549357174461846992529556315682586788137744896985847052668283284231628825924370859640129811142861116994552829398428647",
|
||||
),
|
||||
internal.B10(
|
||||
"100501115016957347491693508757253443864758446032047524096020585354104983606736759639044367167134409576092528219013168507381959241052976704837620234061351712684500077849808223040972825725745511581504906610633548112115513604053190610668096089811015493012026572475283305559529666099836493252485826156659750294903",
|
||||
),
|
||||
internal.B10(
|
||||
"164941338210872461448879529698900150056451305424623398039343691654768566536491493438826728710972441042226712374570117138883019423322602098706113298908005378303473844839971995715847918643285222217768344335264383514921181158565529236124115589719970140511822410990649549555047928093673140752570788415674868532299",
|
||||
),
|
||||
internal.B10(
|
||||
"277037199251333188171108034082127252450960810846571117481542098050121457972964006392527344163695411986229107011168411232117984760439307440561490229321182283823299859836750264962218540927582605520434969388646847458788766216835350519741512353041653865564337457599778511921159510170311560556844284028160928114623",
|
||||
),
|
||||
internal.B10(
|
||||
"194450633495795999995837828580097111229016136925345956148788562473415774074431957758705067019578300241653926511426134047652491974620284426575921711048247821582093564387999309993254763749991516361193554847964638949731507356038181346481870018202492098453036116472375750355687853028597643560794156133662678349939",
|
||||
),
|
||||
internal.B10(
|
||||
"351287943170075259292767465687447861777186026969543801283411356809391771346213158326614410370157474105344692424346410925411240089238093158848815209147605381454294661108047095253146499393310219242924552687094316959878415907497273176683394122976929775532753961555304244867490393116346360677109958055297215711587",
|
||||
),
|
||||
internal.B10(
|
||||
"329970582937843908299463472795994928703202360293919677760100619380642134736439176597341134222679061949935544692834943628667398294307004076774417457697130314341974849843695836050603685013468031012892094273233016929045028941716224648802422408386216033754532303003405690778077639489173685122357063674177077611499",
|
||||
),
|
||||
internal.B10(
|
||||
"67751546105580063387575764356375682499165422473383503143930633584920975946879807021875353514236996076344028719391905234977223693643926924731304657199486141030504275775023186923364159168130612275534168246529309247449138607249407760246378829338068736888203134857601657561860157938495777271164458736576560502603",
|
||||
),
|
||||
internal.B10(
|
||||
"276043923868350639738966705196129285523536747369492013710841410915407411458158268634302674024358477700030814139419613881758439643092328709376796555454484423864587139181985503560495790018232370315219082876142282958894264284344738294415199758590186234114829175455336589153989920707778566032047921277945163061363",
|
||||
),
|
||||
internal.B10(
|
||||
"62028909880050184794454820320289487394141550306616974968340908736543032782344593292214952852576535830823991093496498970213686040280098908204236051130358424961175634703281821899530101130244725435470475135483879784963475148975313832483400747421265545413510460046067002322131902159892876739088034507063542087523",
|
||||
),
|
||||
internal.B10(
|
||||
"321804071508183671133831207712462079740282619152225438240259877528712344129467977098976100894625335474509551113902455258582802291330071887726188174124352664849954838358973904505681968878957681630941310372231688127901147200937955329324769631743029415035218057960201863908173045670622969475867077447909836936523",
|
||||
),
|
||||
internal.B10(
|
||||
"52495647838749571441531580865340679598533348873590977282663145916368795913408897399822291638579504238082829052094508345857857144973446573810004060341650816108578548997792700057865473467391946766537119012441105169305106247003867011741811274367120479722991749924616247396514197345075177297436299446651331187067",
|
||||
),
|
||||
internal.B10(
|
||||
"118753381771703394804894143450628876988609300829627946826004421079000316402854210786451078221445575185505001470635997217855372731401976507648597119694813440063429052266569380936671291883364036649087788968029662592370202444662489071262833666489940296758935970249316300642591963940296755031586580445184253416139",
|
||||
),
|
||||
}
|
||||
|
||||
func TestGenerateChallengesWorks(t *testing.T) {
|
||||
curves := []elliptic.Curve{btcec.S256(), elliptic.P256()}
|
||||
for _, curve := range curves {
|
||||
// dummy secret based on curve
|
||||
y, _ := curves2.NewScalarBaseMult(curve, big.NewInt(3))
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
for j := 0; j < 5; j++ {
|
||||
// Compute N from test primes
|
||||
skN := new(big.Int).Mul(testPrimes[i], testPrimes[j])
|
||||
x, err := generateChallenges(curve.Params(), skN, uint32(i+1), y)
|
||||
|
||||
require.NoError(t, err)
|
||||
for _, xj := range x {
|
||||
require.NotNil(t, xj)
|
||||
require.Greater(t, xj.Cmp(crypto.Zero), 0)
|
||||
require.Equal(t, xj.Cmp(skN), -1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// tests whether the hash function can still produce valid challenges
|
||||
// even when the modulus is smaller than the hash output
|
||||
func TestGenerateChallengesPrimeN(t *testing.T) {
|
||||
curves := []elliptic.Curve{btcec.S256(), elliptic.P256()}
|
||||
n := []*big.Int{
|
||||
internal.B10("680564733841876926926749214863536724007"),
|
||||
internal.B10("1234345830644315716128223123383371693999"),
|
||||
internal.B10(
|
||||
"358070498390900219760227294443948492156530525739357363711230524749453568134007",
|
||||
),
|
||||
internal.B10(
|
||||
"409819537231165473932776844223512813127760876374228481246566335070809195677439",
|
||||
),
|
||||
internal.B10(
|
||||
"336327054820888403283842064345570507895192245801107954728200717775133442039527",
|
||||
),
|
||||
internal.B10(
|
||||
"353526063197730551176241127281213353808518592628930654494044427064787696719527",
|
||||
),
|
||||
}
|
||||
|
||||
for _, curve := range curves {
|
||||
// dummy secret based on curve
|
||||
y, _ := curves2.NewScalarBaseMult(curve, big.NewInt(3))
|
||||
for i := 0; i < 5; i++ {
|
||||
for j := 0; j < 5; j++ {
|
||||
x, err := generateChallenges(curve.Params(), n[i], uint32(j+1), y)
|
||||
|
||||
require.NoError(t, err)
|
||||
for _, xj := range x {
|
||||
require.NotNil(t, xj)
|
||||
require.Greater(t, xj.Cmp(crypto.Zero), 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateChallengesNilInputs(t *testing.T) {
|
||||
y, _ := curves2.NewScalarBaseMult(elliptic.P256(), big.NewInt(1))
|
||||
|
||||
_, err := generateChallenges(nil, nil, 0, nil)
|
||||
require.Error(t, err)
|
||||
_, err = generateChallenges(elliptic.P256().Params(), nil, 0, nil)
|
||||
require.Error(t, err)
|
||||
_, err = generateChallenges(elliptic.P256().Params(), big.NewInt(0), 0, nil)
|
||||
require.Error(t, err)
|
||||
_, err = generateChallenges(elliptic.P256().Params(), big.NewInt(1), 1, nil)
|
||||
require.Error(t, err)
|
||||
_, err = generateChallenges(elliptic.P256().Params(), big.NewInt(1), 1, y)
|
||||
require.Error(t, err)
|
||||
_, err = generateChallenges(elliptic.P256().Params(), big.NewInt(1), 1, y)
|
||||
require.Error(t, err)
|
||||
_, err = generateChallenges(elliptic.P256().Params(), big.NewInt(255), 1, y)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestPsfProofParams_Prove(t *testing.T) {
|
||||
// RSA primes for testing
|
||||
sk, _ := NewSecretKey(
|
||||
// 75-digit random primes from Wolfram-Alpha
|
||||
internal.B10(
|
||||
"110045198697022997120409435651962875820936327127306040565577217116705932648687",
|
||||
),
|
||||
internal.B10(
|
||||
"95848033199746534486927143950536999279071340697368502822602282152563330640779",
|
||||
),
|
||||
)
|
||||
smallSk, _ := NewSecretKey(big.NewInt(13), big.NewInt(11))
|
||||
|
||||
// Some points for testing
|
||||
k := internal.B10("270988338908697209412444309907441365656383309727758604622908325428179708750")
|
||||
Qp256, _ := curves2.NewScalarBaseMult(elliptic.P256(), k)
|
||||
Qs256, _ := curves2.NewScalarBaseMult(btcec.S256(), k)
|
||||
pi := uint32(4)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
in *PsfProofParams
|
||||
expectedError error
|
||||
expectedResultLen int
|
||||
}{
|
||||
// Positive tests
|
||||
{
|
||||
"positive: p256, small numbers",
|
||||
&PsfProofParams{elliptic.P256(), smallSk, 1001, Qp256},
|
||||
nil,
|
||||
PsfProofLength,
|
||||
},
|
||||
{
|
||||
"positive: p256, large numbers",
|
||||
&PsfProofParams{elliptic.P256(), sk, pi, Qp256},
|
||||
nil,
|
||||
PsfProofLength,
|
||||
},
|
||||
{
|
||||
"positive: s256, large numbers",
|
||||
&PsfProofParams{btcec.S256(), sk, pi, Qs256},
|
||||
nil,
|
||||
PsfProofLength,
|
||||
},
|
||||
|
||||
// Nil params
|
||||
{
|
||||
"negative: ",
|
||||
&PsfProofParams{
|
||||
btcec.S256(),
|
||||
sk,
|
||||
pi,
|
||||
Qs256,
|
||||
},
|
||||
nil,
|
||||
PsfProofLength,
|
||||
},
|
||||
{
|
||||
"negative: proof params are nil",
|
||||
&PsfProofParams{
|
||||
nil,
|
||||
sk,
|
||||
pi,
|
||||
Qs256,
|
||||
},
|
||||
internal.ErrNilArguments,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"negative: SecretKey is nil",
|
||||
&PsfProofParams{
|
||||
btcec.S256(),
|
||||
nil,
|
||||
pi,
|
||||
Qs256,
|
||||
},
|
||||
internal.ErrNilArguments,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"negative: y is nil",
|
||||
&PsfProofParams{
|
||||
btcec.S256(),
|
||||
sk,
|
||||
0,
|
||||
Qs256,
|
||||
},
|
||||
internal.ErrNilArguments,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"negative: Pi is nil",
|
||||
&PsfProofParams{
|
||||
btcec.S256(),
|
||||
sk,
|
||||
pi,
|
||||
nil,
|
||||
},
|
||||
internal.ErrNilArguments,
|
||||
0,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
// test
|
||||
result, err := test.in.Prove()
|
||||
|
||||
// Verify the results are as expected
|
||||
require.Equal(t, test.expectedError, err)
|
||||
require.Len(t, result, test.expectedResultLen)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Test that Range2Proof can be marshaled and unmarshaled correctly
|
||||
func TestPsfProof_MarshalJSON(t *testing.T) {
|
||||
// Generate some proof
|
||||
sk, _ := NewSecretKey(
|
||||
internal.B10(
|
||||
"110045198697022997120409435651962875820936327127306040565577217116705932648687",
|
||||
),
|
||||
internal.B10(
|
||||
"95848033199746534486927143950536999279071340697368502822602282152563330640779",
|
||||
),
|
||||
)
|
||||
Q, _ := curves2.NewScalarBaseMult(elliptic.P256(),
|
||||
internal.B10("270988338908697209412444309907441365656383309727758604622908325428179708750"))
|
||||
params := &PsfProofParams{
|
||||
elliptic.P256(), sk,
|
||||
1,
|
||||
Q,
|
||||
}
|
||||
proof, err := params.Prove()
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, proof)
|
||||
|
||||
// Marshal
|
||||
testJSON, err := json.Marshal(proof)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, testJSON)
|
||||
|
||||
var unmarshaled PsfProof
|
||||
err = json.Unmarshal(testJSON, &unmarshaled)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test for equality
|
||||
require.Len(t, ([]*big.Int)(unmarshaled), len(([]*big.Int)(proof)))
|
||||
for i := range proof {
|
||||
require.Equal(t, proof[i], unmarshaled[i])
|
||||
}
|
||||
}
|
||||
|
||||
// Tests for Verify
|
||||
// prove/verify round trip works
|
||||
// modifying any parameter causes verify to fail
|
||||
func TestPsfProofWorks(t *testing.T) {
|
||||
// RSA primes for testing
|
||||
sk, _ := NewSecretKey(
|
||||
// 75-digit random primes from Wolfram-Alpha
|
||||
internal.B10(
|
||||
"110045198697022997120409435651962875820936327127306040565577217116705932648687",
|
||||
),
|
||||
internal.B10(
|
||||
"95848033199746534486927143950536999279071340697368502822602282152563330640779",
|
||||
),
|
||||
)
|
||||
|
||||
// Some points for testing
|
||||
k := internal.B10("270988338908697209412444309907441365656383309727758604622908325428179708750")
|
||||
Qp256, _ := curves2.NewScalarBaseMult(elliptic.P256(), k)
|
||||
pi := uint32(2)
|
||||
|
||||
proveParams := &PsfProofParams{
|
||||
Curve: elliptic.P256(),
|
||||
SecretKey: sk,
|
||||
Pi: pi,
|
||||
Y: Qp256,
|
||||
}
|
||||
proof, _ := proveParams.Prove()
|
||||
verifyParams := &PsfVerifyParams{
|
||||
Curve: elliptic.P256(),
|
||||
PublicKey: &sk.PublicKey,
|
||||
Pi: pi,
|
||||
Y: Qp256,
|
||||
}
|
||||
require.NoError(t, proof.Verify(verifyParams))
|
||||
}
|
||||
Reference in New Issue
Block a user