blob: 48ea776b09163340ad1568e06113b8ad28842fe1 [file] [log] [blame]
#!/usr/bin/env python3
"""
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
"""
"""
This module use cffi to access the c functions in the amcl_mpc library.
"""
import cffi
import platform
import os
ffi = cffi.FFI()
ffi.cdef("""
typedef long unsigned int BIG_512_60[9];
typedef long unsigned int BIG_1024_58[18];
typedef struct {
unsigned int ira[21]; /* random number... */
int rndptr; /* ...array & pointer */
unsigned int borrow;
int pool_ptr;
char pool[32]; /* random pool */
} csprng;
typedef struct
{
int len;
int max;
char *val;
} octet;
/*!
* \brief Paillier Public Key
*/
typedef struct
{
BIG_512_60 n[8]; /**< Paillier Modulus - \f$ n = pq \f$ */
BIG_512_60 g[8]; /**< Public Base - \f$ g = n+1 \f$ */
BIG_512_60 n2[8]; /**< Precomputed \f$ n^2 \f$ */
} PAILLIER_public_key;
/*!
* \brief Paillier Private Key
*/
typedef struct
{
BIG_1024_58 p[1]; /**< Secret Prime */
BIG_1024_58 q[1]; /**< Secret Prime */
BIG_1024_58 lp[1]; /**< Private Key modulo \f$ p \f$ (Euler totient of \f$ p \f$) */
BIG_1024_58 lq[1]; /**< Private Key modulo \f$ q \f$ (Euler totient of \f$ q \f$) */
BIG_1024_58 invp[2]; /**< Precomputed \f$ p^{-1} \pmod{2^m} \f$ */
BIG_1024_58 invq[2]; /**< Precomputed \f$ q^{-1} \pmod{2^m} \f$ */
BIG_1024_58 p2[2]; /**< Precomputed \f$ p^2 \f$ */
BIG_1024_58 q2[2]; /**< Precomputed \f$ q^2 \f$ */
BIG_1024_58 mp[1]; /**< Precomputed \f$ L(g^{lp} \pmod{p^2})^{-1} \f$ */
BIG_1024_58 mq[1]; /**< Precomputed \f$ L(g^{lq} \pmod{q^2})^{-1} \f$ */
} PAILLIER_private_key;
extern void RAND_seed(csprng *R,int n,char *b);
extern void RAND_clean(csprng *R);
extern void OCT_clear(octet *O);
extern void PAILLIER_KEY_PAIR(csprng *RNG, octet *P, octet* Q, PAILLIER_public_key *PUB, PAILLIER_private_key *PRIV);
extern void PAILLIER_PRIVATE_KEY_KILL(PAILLIER_private_key *PRIV);
extern void PAILLIER_PK_toOctet(octet *PK, PAILLIER_public_key *PUB);
extern void PAILLIER_PK_fromOctet(PAILLIER_public_key *PUB, octet *PK);
extern int ECP_SECP256K1_KEY_PAIR_GENERATE(csprng *R,octet *s,octet *W);
extern int ECP_SECP256K1_PUBLIC_KEY_VALIDATE(octet *W);
extern int MPC_ECDSA_VERIFY(octet *HM,octet *PK, octet *R,octet *S);
extern void MPC_MTA_CLIENT1(csprng *RNG, PAILLIER_public_key* PUB, octet* A, octet* CA, octet* R);
extern void MPC_MTA_CLIENT2(PAILLIER_private_key *PRIV, octet* CB, octet *ALPHA);
extern void MPC_MTA_SERVER(csprng *RNG, PAILLIER_public_key *PUB, octet *B, octet *CA, octet *Z, octet *R, octet *CB, octet *BETA);
extern void MPC_SUM_MTA(octet *A, octet *B, octet *ALPHA, octet *BETA, octet *SUM);
extern void MPC_INVKGAMMA(octet *KGAMMA1, octet *KGAMMA2, octet *INVKGAMMA);
extern extern int MPC_R(octet *INVKGAMMA, octet *GAMMAPT1, octet *GAMMAPT2, octet *R, octet *RP);
extern void MPC_HASH(int sha, octet *M, octet *HM);
extern int MPC_S(octet *HM, octet *R, octet *K, octet *SIGMA, octet *S);
extern void MPC_SUM_S(octet *S1, octet *S2, octet *S);
extern int MPC_SUM_PK(octet *PK1, octet *PK2, octet *PK);
extern void MPC_DUMP_PAILLIER_SK(PAILLIER_private_key *PRIV, octet *P, octet *Q);
""")
if (platform.system() == 'Windows'):
libamcl_mpc = ffi.dlopen("libamcl_mpc.dll")
libamcl_paillier = ffi.dlopen("libamcl_paillier.dll")
libamcl_curve_secp256k1 = ffi.dlopen("libamcl_curve_SECP256K1.dll")
libamcl_core = ffi.dlopen("libamcl_core.dll")
elif (platform.system() == 'Darwin'):
libamcl_mpc = ffi.dlopen("libamcl_mpc.dylib")
libamcl_paillier = ffi.dlopen("libamcl_paillier.dylib")
libamcl_curve_secp256k1 = ffi.dlopen("libamcl_curve_SECP256K1.dylib")
libamcl_core = ffi.dlopen("libamcl_core.dylib")
else:
libamcl_mpc = ffi.dlopen("libamcl_mpc.so")
libamcl_paillier = ffi.dlopen("libamcl_paillier.so")
libamcl_curve_secp256k1 = ffi.dlopen("libamcl_curve_SECP256K1.so")
libamcl_core = ffi.dlopen("libamcl_core.so")
# Constants
FS_2048 = 256
HFS_2048 = 128
FS_4096 = 512
EGS_SECP256K1 = 32
EFS_SECP256K1 = 32
SHA256 = 32
curve_order = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
def to_str(octet_value):
"""Converts an octet type into a string
Add all the values in an octet into an array.
Args::
octet_value. An octet pointer type
Returns::
String
Raises:
Exception
"""
i = 0
val = []
while i < octet_value.len:
val.append(octet_value.val[i])
i = i + 1
out = b''
for x in val:
out = out + x
return out
def make_octet(length, value=None):
"""Generates an octet pointer
Generates an empty octet or one filled with the input value
Args::
length: Length of empty octet
value: Data to assign to octet
Returns::
oct_ptr: octet pointer
val: data associated with octet to prevent garbage collection
Raises:
"""
oct_ptr = ffi.new("octet*")
if value:
val = ffi.new("char [%s]" % len(value), value)
oct_ptr.val = val
oct_ptr.max = len(value)
oct_ptr.len = len(value)
else:
val = ffi.new("char []", length)
oct_ptr.val = val
oct_ptr.max = length
oct_ptr.len = length
return oct_ptr, val
def create_csprng(seed):
"""Make a Cryptographically secure pseudo-random number generator instance
Make a Cryptographically secure pseudo-random number generator instance
Args::
seed: random seed value
Returns::
rng: Pointer to cryptographically secure pseudo-random number generator instance
Raises:
"""
seed_val = ffi.new("char [%s]" % len(seed), seed)
seed_len = len(seed)
# random number generator
rng = ffi.new('csprng*')
libamcl_core.RAND_seed(rng, seed_len, seed_val)
return rng
def kill_csprng(rng):
"""Kill a random number generator
Deletes all internal state
Args::
rng: Pointer to cryptographically secure pseudo-random number generator instance
Returns::
Raises:
"""
libamcl_core.RAND_clean(rng)
return 0
def paillier_key_pair(rng, p=None, q=None):
"""Generate Paillier key pair
Generate Paillier key pair
Args::
rng: Pointer to cryptographically secure pseudo-random number generator instance
p: p prime number. Externally generated
q: q prime number. Externally generated
Returns::
paillier_pk: Paillier public key
paillier_sk: Paillier secret key
Raises:
"""
if p:
p1, p1_val = make_octet(None, p)
q1, q1_val = make_octet(None, q)
rng = ffi.NULL
else:
p1 = ffi.NULL
q1 = ffi.NULL
paillier_pk = ffi.new('PAILLIER_public_key*')
paillier_sk = ffi.new('PAILLIER_private_key*')
libamcl_paillier.PAILLIER_KEY_PAIR(rng, p1, q1, paillier_pk, paillier_sk)
return paillier_pk, paillier_sk
def paillier_private_key_kill(paillier_sk):
"""Kill a Paillier secret key
Deletes all internal state
Args::
paillier_sk: Pointer to Paillier secret key
Returns::
Raises:
"""
libamcl_paillier.PAILLIER_PRIVATE_KEY_KILL(PAILLIER_private_key *PRIV);
return 0
def paillier_pk_to_octet(paillier_pk):
"""Write Paillier public key to byte array
Write Paillier public key to byte array
Args::
paillier_pk: Pointer to Paillier public key
Returns::
n: Paillier Modulus - n = pq
Raises:
"""
n1, n1_val = make_octet(FS_4096)
libamcl_paillier.PAILLIER_PK_toOctet(n1, paillier_pk)
n2 = to_str(n1)
return n2
def paillier_pk_from_octet(n):
"""Read Paillier public key from byte array
Read Paillier public key from byte array
Args::
n: Paillier Modulus - n = pq
Returns::
paillier_pk: Pointer to Paillier public key
Raises:
"""
paillier_pk = ffi.new('PAILLIER_public_key*')
n1, n1_val = make_octet(None, n)
libamcl_paillier.PAILLIER_PK_fromOctet(paillier_pk, n1)
return paillier_pk
def ecp_secp256k1_key_pair_generate(rng, ecdsa_sk=None):
"""Generate ECDSA key pair
Generate ECDSA key pair
Args::
rng: Pointer to cryptographically secure pseudo-random number generator instance
ecdsa_sk: secret key input
Returns::
ecdsa_sk: ECDSA secret key
ecdsa_pk: ECDSA public key
rc: Zero for success or else an error code
Raises:
"""
if ecdsa_sk:
ecdsa_sk1, ecdsa_sk1_val = make_octet(None, ecdsa_sk)
rng = ffi.NULL
else:
ecdsa_sk1, ecdsa_sk1_val = make_octet(EGS_SECP256K1)
ecdsa_pk1, ecdsa_pk1_val = make_octet(2 * EFS_SECP256K1)
rc = libamcl_curve_secp256k1.ECP_SECP256K1_KEY_PAIR_GENERATE(rng, ecdsa_sk1, ecdsa_pk1)
ecdsa_sk2 = to_str(ecdsa_sk1)
ecdsa_pk2 = to_str(ecdsa_pk1)
return rc, ecdsa_pk2, ecdsa_sk2
def ecp_secp256k1_public_key_validate(ecdsa_pk):
"""Validate an ECDSA public key
Validate an ECDSA public key
Args::
ecdsa_pk: ECDSA public key
Returns::
rc: Zero for success or else an error code
Raises:
"""
ecdsa_pk1, ecdsa_pk1_val = make_octet(None, ecdsa_pk)
rc = libamcl_curve_secp256k1.ECP_SECP256K1_PUBLIC_KEY_VALIDATE(ecdsa_pk1)
return rc
def mpc_mta_client1(rng, paillier_pk, a, r=None):
"""Client MTA first pass
Client MTA first pass
Args::
rng: Pointer to cryptographically secure pseudo-random number generator instance
paillier_pk: Pointer to Paillier public keys
a: Multiplicative share of secret
r: R value for testing.
Returns::
ca: Ciphertext of additive share of secret
r: R value for testing.
Raises:
"""
if r:
r1, r1_val = make_octet(None, r)
rng = ffi.NULL
else:
r1 = ffi.NULL
a1, a1_val = make_octet(None, a)
ca1, ca1_val = make_octet(FS_4096)
libamcl_mpc.MPC_MTA_CLIENT1(rng, paillier_pk, a1, ca1, r1)
ca2 = to_str(ca1)
return ca2
def mpc_mta_client2(paillier_sk, cb):
"""Client MtA second pass
Client MTA first pass
Args::
paillier_sk: Pointer to Paillier secret key
cb: Ciphertext to decrypt
Returns::
alpha: Additive share of secret
Raises:
"""
cb1, cb1_val = make_octet(None, cb)
alpha1, alpha1_val = make_octet(EGS_SECP256K1)
libamcl_mpc.MPC_MTA_CLIENT2(paillier_sk, cb1, alpha1)
alpha2 = to_str(alpha1)
return alpha2
def mpc_mta_server(rng, paillier_pk, b, ca, z=None, r=None):
"""Server MtA
Server MtA
Args::
rng: Pointer to cryptographically secure pseudo-random number generator instance
paillier_pk: Pointer to Paillier public key
b: Multiplicative share of secret
ca: Ciphertext of client's additive share of secret
z: Negative of beta value used for testing
r: r value for testing.
Returns::
cb: Ciphertext
beta: Additive share of secret
Raises:
"""
if r:
r1, r1_val = make_octet(None, r)
z1, z1_val = make_octet(None, z)
rng = ffi.NULL
else:
r1 = ffi.NULL
z1 = ffi.NULL
b1, b1_val = make_octet(None, b)
ca1, ca1_val = make_octet(None, ca)
beta1, beta1_val = make_octet(EGS_SECP256K1)
cb1, cb1_val = make_octet(FS_4096)
libamcl_mpc.MPC_MTA_SERVER(rng, paillier_pk, b1, ca1, z1, r1, cb1, beta1)
beta2 = to_str(beta1)
cb2 = to_str(cb1)
return cb2, beta2
def mpc_sum_mta(a, b, alpha, beta):
"""Sum of secret shares
Sum of secret shares
Args::
a1: A1 Value
b1: B1 Value
alpha: Additive share of A1.B2
beta: Additive share of A2.B1
Returns::
sum: The sum of all values
Raises:
"""
a1, a1_val = make_octet(None, a)
b1, b1_val = make_octet(None, b)
alpha1, alpha1_val = make_octet(None, alpha)
beta1, beta1_val = make_octet(None, beta)
sum1, sum1_val = make_octet(EGS_SECP256K1)
libamcl_mpc.MPC_SUM_MTA(a1, b1, alpha1, beta1, sum1);
sum2 = to_str(sum1)
return sum2
def mpc_invkgamma(kgamma1, kgamma2):
"""Calculate the inverse of the sum of kgamma values
Calculate the inverse of the sum of kgamma values
Args::
kgamma1: Actor 1 additive share
kgamma2: Actor 2 additive share
Returns::
invkgamma: Inverse of the sum of the additive shares
Raises:
"""
kgamma11, kgamma11_val = make_octet(None, kgamma1)
kgamma21, kgamma21_val = make_octet(None, kgamma2)
invkgamma1, invkgamma1_val = make_octet(EGS_SECP256K1)
libamcl_mpc.MPC_INVKGAMMA(kgamma11, kgamma21, invkgamma1)
invkgamma2 = to_str(invkgamma1)
return invkgamma2
def mpc_r(invkgamma, gammapt1, gammapt2):
"""R component
Generate the ECDSA signature R component
Args::
invkgamma: Inverse of k times gamma
gammapt1: Actor 1 gamma point
gammapt2: Actor 2 gamma point
Returns::
rc: Zero for success or else an error code
r : R component of the signature
rp: ECP associated to R component of signature
Raises:
"""
invkgamma1, invkgamma1_val = make_octet(None, invkgamma)
gammapt11, gammapt11_val = make_octet(None, gammapt1)
gammapt21, gammapt21_val = make_octet(None, gammapt2)
r1, r1_val = make_octet(EGS_SECP256K1)
rp, rp_val = make_octet(EFS_SECP256K1 + 1)
rc = libamcl_mpc.MPC_R(invkgamma1, gammapt11, gammapt21, r1, rp)
r2 = to_str(r1)
rp_str = to_str(rp)
return rc, r2, rp_str
def mpc_hash(message):
"""Hash the message value
Hash the message value using sha256
Args::
message: Message to be hashed
Returns::
hm: hash of message
Raises:
"""
message1, message1_val = make_octet(None, message)
hm1, hm1_val = make_octet(SHA256)
libamcl_mpc.MPC_HASH(SHA256, message1, hm1)
hm2 = to_str(hm1)
return hm2
def mpc_s(hm, r, k, sigma):
"""S component
Generate the ECDSA signature S component
Args::
hm: Hash of the message to be signed
r: r component of signature
k: nonce value
sigma: Additive share of k.w
Returns::
s: s signature component output
rc: Zero for success or else an error code
Raises:
"""
hm1, hm1_val = make_octet(None, hm)
r1, r1_val = make_octet(None, r)
k1, k1_val = make_octet(None, k)
sigma1, sigma1_val = make_octet(None, sigma)
s1, s1_val = make_octet(EGS_SECP256K1)
rc = libamcl_mpc.MPC_S(hm1, r1, k1, sigma1, s1)
s2 = to_str(s1)
return rc, s2
def mpc_ecdsa_verify(hm, pk, r, s):
"""ECDSA Verify signature
Verify the ECDSA signature (R,S) on a message
Args::
hm: Hash of the message to be verify
pk: ecdsa public key
r: r component of signature
s: s component of signature
Returns::
rc: Zero for success or else an error code
Raises:
"""
hm1, hm1_val = make_octet(None, hm)
pk1, pk1_val = make_octet(None, pk)
r1, r1_val = make_octet(None, r)
s1, s1_val = make_octet(None, s)
rc = libamcl_mpc.MPC_ECDSA_VERIFY(hm1, pk1, r1, s1)
return rc
def mpc_sum_s(s1, s2):
"""Sum of ECDSA s components
Calculate the sum of the s components of the ECDSA signature
Args::
s1: Actor 1 ECDSA s component
s2: Actor 2 ECDSA s component
Returns::
s: The sum of all ECDSA s shares
Raises:
"""
s11, s11_val = make_octet(None, s1)
s21, s21_val = make_octet(None, s2)
s1, s1_val = make_octet(EGS_SECP256K1)
libamcl_mpc.MPC_SUM_S(s11, s21, s1);
s2 = to_str(s1)
return s2
def mpc_sum_pk(pk1, pk2):
"""Sum of ECDSA public key shares
Calculate the sum of the ECDSA public key shares
Args::
pk1: Actor 1 ECDSA public key share
pk2: Actor 2 ECDSA public key share
Returns::
pk: The sum of all ECDSA pk shares
rc: Zero for success or else an error code
Raises:
"""
pk11, pk11_val = make_octet(None, pk1)
pk21, pk21_val = make_octet(None, pk2)
pk1, pk1_val = make_octet(EFS_SECP256K1 + 1)
rc = libamcl_mpc.MPC_SUM_PK(pk11, pk21, pk1);
pk2 = to_str(pk1)
return rc, pk2
def mpc_dump_paillier_sk(paillier_sk):
"""Write Paillier public key to byte array
Write Paillier public key to byte array
Args::
paillier_sk: Pointer to Paillier secret key
Returns::
p: Secret prime number
q: Secret prime number
Raises:
"""
p, p_val = make_octet(HFS_2048)
q, q_val = make_octet(HFS_2048)
libamcl_mpc.MPC_DUMP_PAILLIER_SK(paillier_sk, p, q)
p2 = to_str(p)
q2 = to_str(q)
return p2, q2