mirror of
https://github.com/luxfi/tss.git
synced 2026-10-30 15:14:51 +00:00
218 lines
5.1 KiB
Go
218 lines
5.1 KiB
Go
// Copyright © 2019 Binance
|
|
//
|
|
// This file is part of Binance. The full Binance copyright notice, including
|
|
// terms governing use, modification, and redistribution, is contained in the
|
|
// file LICENSE at the root of the source code distribution tree.
|
|
|
|
package mta
|
|
|
|
import (
|
|
"crypto/elliptic"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"math/big"
|
|
|
|
"github.com/luxfi/tss/v2/common"
|
|
"github.com/luxfi/tss/v2/crypto/paillier"
|
|
)
|
|
|
|
const (
|
|
RangeProofAliceBytesParts = 6
|
|
)
|
|
|
|
var (
|
|
zero = big.NewInt(0)
|
|
one = big.NewInt(1)
|
|
)
|
|
|
|
type (
|
|
RangeProofAlice struct {
|
|
Z, U, W, S, S1, S2 *big.Int
|
|
}
|
|
)
|
|
|
|
// ProveRangeAlice implements Alice's range proof used in the MtA and MtAwc protocols from GG18Spec (9) Fig. 9.
|
|
func ProveRangeAlice(ec elliptic.Curve, pk *paillier.PublicKey, c, NTilde, h1, h2, m, r *big.Int, rand io.Reader) (*RangeProofAlice, error) {
|
|
if pk == nil || NTilde == nil || h1 == nil || h2 == nil || c == nil || m == nil || r == nil {
|
|
return nil, errors.New("ProveRangeAlice constructor received nil value(s)")
|
|
}
|
|
|
|
q := ec.Params().N
|
|
q3 := new(big.Int).Mul(q, q)
|
|
q3 = new(big.Int).Mul(q, q3)
|
|
qNTilde := new(big.Int).Mul(q, NTilde)
|
|
q3NTilde := new(big.Int).Mul(q3, NTilde)
|
|
|
|
// 1.
|
|
alpha := common.GetRandomPositiveInt(rand, q3)
|
|
// 2.
|
|
beta := common.GetRandomPositiveRelativelyPrimeInt(rand, pk.N)
|
|
|
|
// 3.
|
|
gamma := common.GetRandomPositiveInt(rand, q3NTilde)
|
|
|
|
// 4.
|
|
rho := common.GetRandomPositiveInt(rand, qNTilde)
|
|
|
|
// 5.
|
|
modNTilde := common.ModInt(NTilde)
|
|
z := modNTilde.Exp(h1, m)
|
|
z = modNTilde.Mul(z, modNTilde.Exp(h2, rho))
|
|
|
|
// 6.
|
|
modNSquared := common.ModInt(pk.NSquare())
|
|
u := modNSquared.Exp(pk.Gamma(), alpha)
|
|
u = modNSquared.Mul(u, modNSquared.Exp(beta, pk.N))
|
|
|
|
// 7.
|
|
w := modNTilde.Exp(h1, alpha)
|
|
w = modNTilde.Mul(w, modNTilde.Exp(h2, gamma))
|
|
|
|
// 8-9. e'
|
|
var e *big.Int
|
|
{ // must use RejectionSample
|
|
eHash := common.SHA512_256i(append(pk.AsInts(), c, z, u, w)...)
|
|
e = common.RejectionSample(q, eHash)
|
|
}
|
|
|
|
modN := common.ModInt(pk.N)
|
|
s := modN.Exp(r, e)
|
|
s = modN.Mul(s, beta)
|
|
|
|
// s1 = e * m + alpha
|
|
s1 := new(big.Int).Mul(e, m)
|
|
s1 = new(big.Int).Add(s1, alpha)
|
|
|
|
// s2 = e * rho + gamma
|
|
s2 := new(big.Int).Mul(e, rho)
|
|
s2 = new(big.Int).Add(s2, gamma)
|
|
|
|
return &RangeProofAlice{Z: z, U: u, W: w, S: s, S1: s1, S2: s2}, nil
|
|
}
|
|
|
|
func RangeProofAliceFromBytes(bzs [][]byte) (*RangeProofAlice, error) {
|
|
if !common.NonEmptyMultiBytes(bzs, RangeProofAliceBytesParts) {
|
|
return nil, fmt.Errorf("expected %d byte parts to construct RangeProofAlice", RangeProofAliceBytesParts)
|
|
}
|
|
return &RangeProofAlice{
|
|
Z: new(big.Int).SetBytes(bzs[0]),
|
|
U: new(big.Int).SetBytes(bzs[1]),
|
|
W: new(big.Int).SetBytes(bzs[2]),
|
|
S: new(big.Int).SetBytes(bzs[3]),
|
|
S1: new(big.Int).SetBytes(bzs[4]),
|
|
S2: new(big.Int).SetBytes(bzs[5]),
|
|
}, nil
|
|
}
|
|
|
|
func (pf *RangeProofAlice) Verify(ec elliptic.Curve, pk *paillier.PublicKey, NTilde, h1, h2, c *big.Int) bool {
|
|
if pf == nil || !pf.ValidateBasic() || pk == nil || NTilde == nil || h1 == nil || h2 == nil || c == nil {
|
|
return false
|
|
}
|
|
|
|
q := ec.Params().N
|
|
q3 := new(big.Int).Mul(q, q)
|
|
q3 = new(big.Int).Mul(q, q3)
|
|
|
|
if !common.IsInInterval(pf.Z, NTilde) {
|
|
return false
|
|
}
|
|
if !common.IsInInterval(pf.U, pk.NSquare()) {
|
|
return false
|
|
}
|
|
if !common.IsInInterval(pf.W, NTilde) {
|
|
return false
|
|
}
|
|
if !common.IsInInterval(pf.S, pk.N) {
|
|
return false
|
|
}
|
|
if new(big.Int).GCD(nil, nil, pf.Z, NTilde).Cmp(one) != 0 {
|
|
return false
|
|
}
|
|
if new(big.Int).GCD(nil, nil, pf.U, pk.NSquare()).Cmp(one) != 0 {
|
|
return false
|
|
}
|
|
if new(big.Int).GCD(nil, nil, pf.W, NTilde).Cmp(one) != 0 {
|
|
return false
|
|
}
|
|
if pf.S1.Cmp(q) == -1 {
|
|
return false
|
|
}
|
|
if pf.S2.Cmp(q) == -1 {
|
|
return false
|
|
}
|
|
if pf.S.Cmp(one) == 0 {
|
|
return false
|
|
}
|
|
if pf.Z.Cmp(one) == 0 {
|
|
return false
|
|
}
|
|
if pf.S1.Cmp(pf.S2) == 0 {
|
|
return false
|
|
}
|
|
|
|
// 3.
|
|
if pf.S1.Cmp(q3) == 1 {
|
|
return false
|
|
}
|
|
|
|
// 1-2. e'
|
|
var e *big.Int
|
|
{ // must use RejectionSample
|
|
eHash := common.SHA512_256i(append(pk.AsInts(), c, pf.Z, pf.U, pf.W)...)
|
|
e = common.RejectionSample(q, eHash)
|
|
}
|
|
|
|
var products *big.Int // for the following conditionals
|
|
minusE := new(big.Int).Sub(zero, e)
|
|
|
|
{ // 4. gamma^s_1 * s^N * c^-e
|
|
modNSquared := common.ModInt(pk.NSquare())
|
|
|
|
cExpMinusE := modNSquared.Exp(c, minusE)
|
|
sExpN := modNSquared.Exp(pf.S, pk.N)
|
|
gammaExpS1 := modNSquared.Exp(pk.Gamma(), pf.S1)
|
|
// u != (4)
|
|
products = modNSquared.Mul(gammaExpS1, sExpN)
|
|
products = modNSquared.Mul(products, cExpMinusE)
|
|
if pf.U.Cmp(products) != 0 {
|
|
return false
|
|
}
|
|
}
|
|
|
|
{ // 5. h_1^s_1 * h_2^s_2 * z^-e
|
|
modNTilde := common.ModInt(NTilde)
|
|
|
|
h1ExpS1 := modNTilde.Exp(h1, pf.S1)
|
|
h2ExpS2 := modNTilde.Exp(h2, pf.S2)
|
|
zExpMinusE := modNTilde.Exp(pf.Z, minusE)
|
|
// w != (5)
|
|
products = modNTilde.Mul(h1ExpS1, h2ExpS2)
|
|
products = modNTilde.Mul(products, zExpMinusE)
|
|
if pf.W.Cmp(products) != 0 {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (pf *RangeProofAlice) ValidateBasic() bool {
|
|
return pf.Z != nil &&
|
|
pf.U != nil &&
|
|
pf.W != nil &&
|
|
pf.S != nil &&
|
|
pf.S1 != nil &&
|
|
pf.S2 != nil
|
|
}
|
|
|
|
func (pf *RangeProofAlice) Bytes() [RangeProofAliceBytesParts][]byte {
|
|
return [...][]byte{
|
|
pf.Z.Bytes(),
|
|
pf.U.Bytes(),
|
|
pf.W.Bytes(),
|
|
pf.S.Bytes(),
|
|
pf.S1.Bytes(),
|
|
pf.S2.Bytes(),
|
|
}
|
|
}
|