mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 21:31:37 +00:00
1376 lines
36 KiB
Go
1376 lines
36 KiB
Go
package privacy
|
|
|
|
import (
|
|
"crypto/ecdsa"
|
|
"crypto/elliptic"
|
|
"crypto/rand"
|
|
"crypto/sha256"
|
|
"encoding/binary"
|
|
"errors"
|
|
"fmt"
|
|
"math"
|
|
"math/big"
|
|
"strconv"
|
|
|
|
"github.com/XinFinOrg/XDPoSChain/common"
|
|
"github.com/XinFinOrg/XDPoSChain/log"
|
|
|
|
"github.com/XinFinOrg/XDPoSChain/crypto"
|
|
"github.com/btcsuite/btcd/btcec/v2"
|
|
)
|
|
|
|
type Bulletproof struct {
|
|
proofData []byte
|
|
}
|
|
|
|
var EC CryptoParams
|
|
var VecLength = 512 // support maximum 8 spending value, each 64 bit (gwei is unit)
|
|
var curve elliptic.Curve = crypto.S256()
|
|
|
|
/*
|
|
Implementation of BulletProofs
|
|
*/
|
|
type ECPoint struct {
|
|
X, Y *big.Int
|
|
}
|
|
|
|
func (p *ECPoint) toECPubKey() *ecdsa.PublicKey {
|
|
return &ecdsa.PublicKey{
|
|
Curve: curve,
|
|
X: p.X,
|
|
Y: p.Y,
|
|
}
|
|
}
|
|
|
|
func toECPoint(key *ecdsa.PublicKey) *ECPoint {
|
|
return &ECPoint{key.X, key.Y}
|
|
}
|
|
|
|
// Equal returns true if points p (self) and p2 (arg) are the same.
|
|
func (p ECPoint) Equal(p2 ECPoint) bool {
|
|
if p.X.Cmp(p2.X) == 0 && p2.Y.Cmp(p2.Y) == 0 {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Mult multiplies point p by scalar s and returns the resulting point
|
|
func (p ECPoint) Mult(s *big.Int) ECPoint {
|
|
modS := new(big.Int).Mod(s, EC.N)
|
|
X, Y := EC.C.ScalarMult(p.X, p.Y, modS.Bytes())
|
|
return ECPoint{X, Y}
|
|
}
|
|
|
|
// Add adds points p and p2 and returns the resulting point
|
|
func (p ECPoint) Add(p2 ECPoint) ECPoint {
|
|
X, Y := EC.C.Add(p.X, p.Y, p2.X, p2.Y)
|
|
return ECPoint{X, Y}
|
|
}
|
|
|
|
// Neg returns the additive inverse of point p
|
|
func (p ECPoint) Neg() ECPoint {
|
|
negY := new(big.Int).Neg(p.Y)
|
|
modValue := negY.Mod(negY, EC.C.Params().P) // mod P is fine here because we're describing a curve point
|
|
return ECPoint{p.X, modValue}
|
|
}
|
|
|
|
type CryptoParams struct {
|
|
C elliptic.Curve // curve
|
|
KC *btcec.KoblitzCurve // curve
|
|
BPG []ECPoint // slice of gen 1 for BP
|
|
BPH []ECPoint // slice of gen 2 for BP
|
|
N *big.Int // scalar prime
|
|
U ECPoint // a point that is a fixed group element with an unknown discrete-log relative to g,h
|
|
V int // Vector length
|
|
G ECPoint // G value for commitments of a single value
|
|
H ECPoint // H value for commitments of a single value
|
|
}
|
|
|
|
func (c CryptoParams) Zero() ECPoint {
|
|
return ECPoint{big.NewInt(0), big.NewInt(0)}
|
|
}
|
|
|
|
func check(e error) {
|
|
if e != nil {
|
|
panic(e)
|
|
}
|
|
}
|
|
|
|
/*
|
|
Vector Pedersen Commitment
|
|
Given an array of values, we commit the array with different generators
|
|
for each element and for each randomness.
|
|
*/
|
|
func VectorPCommit(value []*big.Int) (ECPoint, []*big.Int) {
|
|
R := make([]*big.Int, EC.V)
|
|
|
|
commitment := EC.Zero()
|
|
|
|
for i := 0; i < EC.V; i++ {
|
|
r, err := rand.Int(rand.Reader, EC.N)
|
|
check(err)
|
|
|
|
R[i] = r
|
|
|
|
modValue := new(big.Int).Mod(value[i], EC.N)
|
|
|
|
// mG, rH
|
|
lhsX, lhsY := EC.C.ScalarMult(EC.BPG[i].X, EC.BPG[i].Y, modValue.Bytes())
|
|
rhsX, rhsY := EC.C.ScalarMult(EC.BPH[i].X, EC.BPH[i].Y, r.Bytes())
|
|
|
|
commitment = commitment.Add(ECPoint{lhsX, lhsY}).Add(ECPoint{rhsX, rhsY})
|
|
}
|
|
|
|
return commitment, R
|
|
}
|
|
|
|
/*
|
|
Two Vector P Commit
|
|
Given an array of values, we commit the array with different generators
|
|
for each element and for each randomness.
|
|
*/
|
|
func TwoVectorPCommit(a []*big.Int, b []*big.Int) ECPoint {
|
|
if len(a) != len(b) {
|
|
log.Debug("TwoVectorPCommit: Arrays not of the same length", "len(a)", len(a), "len(b)", len(b))
|
|
}
|
|
|
|
commitment := EC.Zero()
|
|
|
|
for i := 0; i < EC.V; i++ {
|
|
commitment = commitment.Add(EC.BPG[i].Mult(a[i])).Add(EC.BPH[i].Mult(b[i]))
|
|
}
|
|
|
|
return commitment
|
|
}
|
|
|
|
/*
|
|
Vector Pedersen Commitment with Gens
|
|
Given an array of values, we commit the array with different generators
|
|
for each element and for each randomness.
|
|
We also pass in the Generators we want to use
|
|
*/
|
|
func TwoVectorPCommitWithGens(G, H []ECPoint, a, b []*big.Int) ECPoint {
|
|
if len(G) != len(H) || len(G) != len(a) || len(a) != len(b) {
|
|
log.Debug("TwoVectorPCommitWithGens: Arrays not of the same length", "len(G)", len(G), "len(H)", len(H), "len(a)", len(a), "len(b)", len(b))
|
|
}
|
|
|
|
commitment := EC.Zero()
|
|
|
|
for i := 0; i < len(G); i++ {
|
|
modA := new(big.Int).Mod(a[i], EC.N)
|
|
modB := new(big.Int).Mod(b[i], EC.N)
|
|
|
|
commitment = commitment.Add(G[i].Mult(modA)).Add(H[i].Mult(modB))
|
|
}
|
|
|
|
return commitment
|
|
}
|
|
|
|
// The length here always has to be a power of two
|
|
func InnerProduct(a []*big.Int, b []*big.Int) *big.Int {
|
|
if len(a) != len(b) {
|
|
log.Debug("InnerProduct: Arrays not of the same length", "len(a)", len(a), "len(b", len(b))
|
|
}
|
|
|
|
c := big.NewInt(0)
|
|
|
|
for i := range a {
|
|
tmp1 := new(big.Int).Mul(a[i], b[i])
|
|
c = new(big.Int).Add(c, new(big.Int).Mod(tmp1, EC.N))
|
|
}
|
|
|
|
return new(big.Int).Mod(c, EC.N)
|
|
}
|
|
|
|
func VectorAdd(v []*big.Int, w []*big.Int) []*big.Int {
|
|
if len(v) != len(w) {
|
|
log.Debug("VectorAdd: Arrays not of the same length", "len(v)", len(v), "len(w)", len(w))
|
|
}
|
|
result := make([]*big.Int, len(v))
|
|
|
|
for i := range v {
|
|
result[i] = new(big.Int).Mod(new(big.Int).Add(v[i], w[i]), EC.N)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func VectorHadamard(v, w []*big.Int) []*big.Int {
|
|
if len(v) != len(w) {
|
|
log.Debug("VectorHadamard: Arrays not of the same length", "len(v)", len(v), "len(w)", len(w))
|
|
}
|
|
|
|
result := make([]*big.Int, len(v))
|
|
|
|
for i := range v {
|
|
result[i] = new(big.Int).Mod(new(big.Int).Mul(v[i], w[i]), EC.N)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func VectorAddScalar(v []*big.Int, s *big.Int) []*big.Int {
|
|
result := make([]*big.Int, len(v))
|
|
|
|
for i := range v {
|
|
result[i] = new(big.Int).Mod(new(big.Int).Add(v[i], s), EC.N)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func ScalarVectorMul(v []*big.Int, s *big.Int) []*big.Int {
|
|
result := make([]*big.Int, len(v))
|
|
|
|
for i := range v {
|
|
result[i] = new(big.Int).Mod(new(big.Int).Mul(v[i], s), EC.N)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func HashPointsToBytes(points []ECPoint) []byte {
|
|
input := []byte{}
|
|
|
|
for index := 0; index < len(points); index++ {
|
|
pointInByte := append(PadTo32Bytes(points[index].X.Bytes()), PadTo32Bytes(points[index].Y.Bytes())...)
|
|
input = append(input, pointInByte...)
|
|
}
|
|
|
|
return crypto.Keccak256(input)
|
|
}
|
|
|
|
/*
|
|
InnerProd Proof
|
|
This stores the argument values
|
|
*/
|
|
type InnerProdArg struct {
|
|
L []ECPoint
|
|
R []ECPoint
|
|
A *big.Int
|
|
B *big.Int
|
|
|
|
Challenges []*big.Int
|
|
}
|
|
|
|
func GenerateNewParams(G, H []ECPoint, x *big.Int, L, R, P ECPoint) ([]ECPoint, []ECPoint, ECPoint) {
|
|
nprime := len(G) / 2
|
|
|
|
Gprime := make([]ECPoint, nprime)
|
|
Hprime := make([]ECPoint, nprime)
|
|
|
|
xinv := new(big.Int).ModInverse(x, EC.N)
|
|
|
|
// Gprime = xinv * G[:nprime] + x*G[nprime:]
|
|
// Hprime = x * H[:nprime] + xinv*H[nprime:]
|
|
|
|
for i := range Gprime {
|
|
//fmt.Printf("i: %d && i+nprime: %d\n", i, i+nprime)
|
|
Gprime[i] = G[i].Mult(xinv).Add(G[i+nprime].Mult(x))
|
|
Hprime[i] = H[i].Mult(x).Add(H[i+nprime].Mult(xinv))
|
|
}
|
|
|
|
x2 := new(big.Int).Mod(new(big.Int).Mul(x, x), EC.N)
|
|
xinv2 := new(big.Int).ModInverse(x2, EC.N)
|
|
|
|
Pprime := L.Mult(x2).Add(P).Add(R.Mult(xinv2)) // x^2 * L + P + xinv^2 * R
|
|
|
|
return Gprime, Hprime, Pprime
|
|
}
|
|
|
|
/*
|
|
Inner Product Argument
|
|
|
|
Proves that <a,b>=c
|
|
This is a building block for BulletProofs
|
|
*/
|
|
func InnerProductProveSub(proof InnerProdArg, G, H []ECPoint, a []*big.Int, b []*big.Int, u ECPoint, P ECPoint) InnerProdArg {
|
|
if len(a) == 1 {
|
|
// Prover sends a & b
|
|
proof.A = a[0]
|
|
proof.B = b[0]
|
|
return proof
|
|
}
|
|
|
|
curIt := int(math.Log2(float64(len(a)))) - 1
|
|
|
|
nprime := len(a) / 2
|
|
cl := InnerProduct(a[:nprime], b[nprime:]) // either this line
|
|
cr := InnerProduct(a[nprime:], b[:nprime]) // or this line
|
|
L := TwoVectorPCommitWithGens(G[nprime:], H[:nprime], a[:nprime], b[nprime:]).Add(u.Mult(cl))
|
|
R := TwoVectorPCommitWithGens(G[:nprime], H[nprime:], a[nprime:], b[:nprime]).Add(u.Mult(cr))
|
|
|
|
proof.L[curIt] = L
|
|
proof.R[curIt] = R
|
|
|
|
// prover sends L & R and gets a challenge
|
|
// LvalInBytes := append(PadTo32Bytes(L.X.Bytes()), PadTo32Bytes(L.Y.Bytes())...)
|
|
// RvalInBytes := append(PadTo32Bytes(R.X.Bytes()), PadTo32Bytes(R.Y.Bytes())...)
|
|
// input := append(LvalInBytes, RvalInBytes...)
|
|
// s256 := crypto.Keccak256(input)
|
|
s256 := HashPointsToBytes([]ECPoint{L, R})
|
|
|
|
x := new(big.Int).SetBytes(s256[:])
|
|
|
|
proof.Challenges[curIt] = x
|
|
|
|
Gprime, Hprime, Pprime := GenerateNewParams(G, H, x, L, R, P)
|
|
|
|
xinv := new(big.Int).ModInverse(x, EC.N)
|
|
|
|
// or these two lines
|
|
aprime := VectorAdd(
|
|
ScalarVectorMul(a[:nprime], x),
|
|
ScalarVectorMul(a[nprime:], xinv))
|
|
bprime := VectorAdd(
|
|
ScalarVectorMul(b[:nprime], xinv),
|
|
ScalarVectorMul(b[nprime:], x))
|
|
|
|
return InnerProductProveSub(proof, Gprime, Hprime, aprime, bprime, u, Pprime)
|
|
}
|
|
|
|
// rpresult.IPP = InnerProductProve(left, right, that, P, EC.U, EC.BPG, HPrime)
|
|
func InnerProductProve(a []*big.Int, b []*big.Int, c *big.Int, P, U ECPoint, G, H []ECPoint) InnerProdArg {
|
|
loglen := int(math.Log2(float64(len(a))))
|
|
|
|
challenges := make([]*big.Int, loglen+1)
|
|
Lvals := make([]ECPoint, loglen)
|
|
Rvals := make([]ECPoint, loglen)
|
|
|
|
runningProof := InnerProdArg{
|
|
Lvals,
|
|
Rvals,
|
|
big.NewInt(0),
|
|
big.NewInt(0),
|
|
challenges}
|
|
|
|
// randomly generate an x value from public data
|
|
// input := append(PadTo32Bytes(P.X.Bytes()), PadTo32Bytes(P.Y.Bytes())...)
|
|
// x := crypto.Keccak256(input)
|
|
x := HashPointsToBytes([]ECPoint{P})
|
|
|
|
runningProof.Challenges[loglen] = new(big.Int).SetBytes(x[:])
|
|
|
|
Pprime := P.Add(U.Mult(new(big.Int).Mul(new(big.Int).SetBytes(x[:]), c)))
|
|
|
|
ux := U.Mult(new(big.Int).SetBytes(x[:]))
|
|
//fmt.Printf("Prover Pprime value to run sub off of: %s\n", Pprime)
|
|
|
|
return InnerProductProveSub(runningProof, G, H, a, b, ux, Pprime)
|
|
}
|
|
|
|
/*
|
|
Inner Product Verify
|
|
|
|
Given a inner product proof, verifies the correctness of the proof
|
|
Since we're using the Fiat-Shamir transform, we need to verify all x hash computations,
|
|
all g' and h' computations
|
|
P : the Pedersen commitment we are verifying is a commitment to the innner product
|
|
ipp : the proof
|
|
*/
|
|
func InnerProductVerify(c *big.Int, P, U ECPoint, G, H []ECPoint, ipp InnerProdArg) bool {
|
|
//fmt.Println("Verifying Inner Product Argument")
|
|
//fmt.Printf("Commitment Value: %s \n", P)
|
|
// s1 := sha256.Sum256([]byte(P.X.String() + P.Y.String()))
|
|
|
|
// input := append(PadTo32Bytes(P.X.Bytes()), PadTo32Bytes(P.Y.Bytes())...)
|
|
// s1 := crypto.Keccak256(input)
|
|
s1 := HashPointsToBytes([]ECPoint{P})
|
|
|
|
chal1 := new(big.Int).SetBytes(s1[:])
|
|
ux := U.Mult(chal1)
|
|
curIt := len(ipp.Challenges) - 1
|
|
|
|
if ipp.Challenges[curIt].Cmp(chal1) != 0 {
|
|
log.Info("Initial Challenge Failed")
|
|
return false
|
|
}
|
|
|
|
curIt -= 1
|
|
|
|
Gprime := G
|
|
Hprime := H
|
|
Pprime := P.Add(ux.Mult(c)) // line 6 from protocol 1
|
|
//fmt.Printf("New Commitment value with u^cx: %s \n", Pprime)
|
|
|
|
for curIt >= 0 {
|
|
Lval := ipp.L[curIt]
|
|
Rval := ipp.R[curIt]
|
|
|
|
// prover sends L & R and gets a challenge
|
|
// s256 := sha256.Sum256([]byte(
|
|
// Lval.X.String() + Lval.Y.String() +
|
|
// Rval.X.String() + Rval.Y.String()))
|
|
// LvalInBytes := append(PadTo32Bytes(Lval.X.Bytes()), PadTo32Bytes(Lval.Y.Bytes())...)
|
|
// RvalInBytes := append(PadTo32Bytes(Rval.X.Bytes()), PadTo32Bytes(Rval.Y.Bytes())...)
|
|
// input := append(LvalInBytes, RvalInBytes...)
|
|
// s256 := crypto.Keccak256(input)
|
|
s256 := HashPointsToBytes([]ECPoint{Lval, Rval})
|
|
|
|
chal2 := new(big.Int).SetBytes(s256[:])
|
|
|
|
if ipp.Challenges[curIt].Cmp(chal2) != 0 {
|
|
log.Info("Challenge verification failed", "index", strconv.Itoa(curIt))
|
|
return false
|
|
}
|
|
|
|
Gprime, Hprime, Pprime = GenerateNewParams(Gprime, Hprime, chal2, Lval, Rval, Pprime)
|
|
curIt -= 1
|
|
}
|
|
ccalc := new(big.Int).Mod(new(big.Int).Mul(ipp.A, ipp.B), EC.N)
|
|
|
|
Pcalc1 := Gprime[0].Mult(ipp.A)
|
|
Pcalc2 := Hprime[0].Mult(ipp.B)
|
|
Pcalc3 := ux.Mult(ccalc)
|
|
Pcalc := Pcalc1.Add(Pcalc2).Add(Pcalc3)
|
|
|
|
return Pprime.Equal(Pcalc)
|
|
}
|
|
|
|
/* Inner Product Verify Fast
|
|
Given a inner product proof, verifies the correctness of the proof. Does the same as above except
|
|
we replace n separate exponentiations with a single multi-exponentiation.
|
|
*/
|
|
|
|
func InnerProductVerifyFast(c *big.Int, P, U ECPoint, G, H []ECPoint, ipp InnerProdArg) bool {
|
|
// input := append(PadTo32Bytes(P.X.Bytes()), PadTo32Bytes(P.Y.Bytes())...)
|
|
// s1 := crypto.Keccak256(input)
|
|
s1 := HashPointsToBytes([]ECPoint{P})
|
|
|
|
chal1 := new(big.Int).SetBytes(s1[:])
|
|
ux := U.Mult(chal1)
|
|
curIt := len(ipp.Challenges) - 1
|
|
|
|
// check all challenges
|
|
if ipp.Challenges[curIt].Cmp(chal1) != 0 {
|
|
log.Debug("Initial Challenge Failed")
|
|
return false
|
|
}
|
|
|
|
for j := curIt - 1; j >= 0; j-- {
|
|
Lval := ipp.L[j]
|
|
Rval := ipp.R[j]
|
|
|
|
// prover sends L & R and gets a challenge
|
|
// LvalInBytes := append(PadTo32Bytes(Lval.X.Bytes()), PadTo32Bytes(Lval.Y.Bytes())...)
|
|
// RvalInBytes := append(PadTo32Bytes(Rval.X.Bytes()), PadTo32Bytes(Rval.Y.Bytes())...)
|
|
// input := append(LvalInBytes, RvalInBytes...)
|
|
// s256 := crypto.Keccak256(input)
|
|
s256 := HashPointsToBytes([]ECPoint{Lval, Rval})
|
|
|
|
chal2 := new(big.Int).SetBytes(s256[:])
|
|
|
|
if ipp.Challenges[j].Cmp(chal2) != 0 {
|
|
log.Debug("Challenge verification failed", "index", strconv.Itoa(j))
|
|
return false
|
|
}
|
|
}
|
|
// begin computing
|
|
|
|
curIt -= 1
|
|
Pprime := P.Add(ux.Mult(c)) // line 6 from protocol 1
|
|
|
|
tmp1 := EC.Zero()
|
|
for j := curIt; j >= 0; j-- {
|
|
x2 := new(big.Int).Exp(ipp.Challenges[j], big.NewInt(2), EC.N)
|
|
x2i := new(big.Int).ModInverse(x2, EC.N)
|
|
//fmt.Println(tmp1)
|
|
tmp1 = ipp.L[j].Mult(x2).Add(ipp.R[j].Mult(x2i)).Add(tmp1)
|
|
//fmt.Println(tmp1)
|
|
}
|
|
rhs := Pprime.Add(tmp1)
|
|
//rhs=P+c*ux + L*xw+R*x2i 公式29
|
|
|
|
sScalars := make([]*big.Int, EC.V)
|
|
invsScalars := make([]*big.Int, EC.V)
|
|
|
|
for i := 0; i < EC.V; i++ {
|
|
si := big.NewInt(1)
|
|
for j := curIt; j >= 0; j-- {
|
|
// original challenge if the jth bit of i is 1, inverse challenge otherwise
|
|
chal := ipp.Challenges[j]
|
|
if big.NewInt(int64(i)).Bit(j) == 0 {
|
|
chal = new(big.Int).ModInverse(chal, EC.N)
|
|
}
|
|
// fmt.Printf("Challenge raised to value: %d\n", chal)
|
|
si = new(big.Int).Mod(new(big.Int).Mul(si, chal), EC.N)
|
|
}
|
|
//fmt.Printf("Si value: %d\n", si)
|
|
sScalars[i] = si
|
|
invsScalars[i] = new(big.Int).ModInverse(si, EC.N)
|
|
}
|
|
|
|
ccalc := new(big.Int).Mod(new(big.Int).Mul(ipp.A, ipp.B), EC.N)
|
|
lhs := TwoVectorPCommitWithGens(G, H, ScalarVectorMul(sScalars, ipp.A), ScalarVectorMul(invsScalars, ipp.B)).Add(ux.Mult(ccalc))
|
|
|
|
if !rhs.Equal(lhs) {
|
|
log.Info("IPVerify - Final Commitment checking failed")
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// from here: https://play.golang.org/p/zciRZvD0Gr with a fix
|
|
func PadLeft(str, pad string, l int) string {
|
|
strCopy := str
|
|
for len(strCopy) < l {
|
|
strCopy = pad + strCopy
|
|
}
|
|
|
|
return strCopy
|
|
}
|
|
|
|
func STRNot(str string) string {
|
|
result := ""
|
|
|
|
for _, i := range str {
|
|
if i == '0' {
|
|
result += "1"
|
|
} else {
|
|
result += "0"
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func StrToBigIntArray(str string) []*big.Int {
|
|
result := make([]*big.Int, len(str))
|
|
|
|
for i := range str {
|
|
t, success := new(big.Int).SetString(string(str[i]), 10)
|
|
if success {
|
|
result[i] = t
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func reverse(l []*big.Int) []*big.Int {
|
|
result := make([]*big.Int, len(l))
|
|
|
|
for i := range l {
|
|
result[i] = l[len(l)-i-1]
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func PowerVector(l int, base *big.Int) []*big.Int {
|
|
result := make([]*big.Int, l)
|
|
|
|
for i := 0; i < l; i++ {
|
|
result[i] = new(big.Int).Exp(base, big.NewInt(int64(i)), EC.N)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func RandVector(l int) []*big.Int {
|
|
result := make([]*big.Int, l)
|
|
|
|
for i := 0; i < l; i++ {
|
|
x, err := rand.Int(rand.Reader, EC.N)
|
|
check(err)
|
|
result[i] = x
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func VectorSum(y []*big.Int) *big.Int {
|
|
result := big.NewInt(0)
|
|
|
|
for _, j := range y {
|
|
result = new(big.Int).Mod(new(big.Int).Add(result, j), EC.N)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
type RangeProof struct {
|
|
Comm ECPoint
|
|
A ECPoint
|
|
S ECPoint
|
|
T1 ECPoint
|
|
T2 ECPoint
|
|
Tau *big.Int
|
|
Th *big.Int
|
|
Mu *big.Int
|
|
IPP InnerProdArg
|
|
|
|
// challenges
|
|
Cy *big.Int
|
|
Cz *big.Int
|
|
Cx *big.Int
|
|
}
|
|
|
|
/*
|
|
Delta is a helper function that is used in the range proof
|
|
\delta(y, z) = (z-z^2)<1^n, y^n> - z^3<1^n, 2^n>
|
|
*/
|
|
|
|
func Delta(y []*big.Int, z *big.Int) *big.Int {
|
|
// (z-z^2)<1^n, y^n>
|
|
z2 := new(big.Int).Mod(new(big.Int).Mul(z, z), EC.N)
|
|
t1 := new(big.Int).Mod(new(big.Int).Sub(z, z2), EC.N)
|
|
t2 := new(big.Int).Mod(new(big.Int).Mul(t1, VectorSum(y)), EC.N)
|
|
|
|
// z^3<1^n, 2^n>
|
|
z3 := new(big.Int).Mod(new(big.Int).Mul(z2, z), EC.N)
|
|
po2sum := new(big.Int).Sub(new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(EC.V)), EC.N), big.NewInt(1))
|
|
t3 := new(big.Int).Mod(new(big.Int).Mul(z3, po2sum), EC.N)
|
|
|
|
return new(big.Int).Mod(new(big.Int).Sub(t2, t3), EC.N)
|
|
}
|
|
|
|
// Calculates (aL - z*1^n) + sL*x
|
|
func CalculateL(aL, sL []*big.Int, z, x *big.Int) []*big.Int {
|
|
tmp1 := VectorAddScalar(aL, new(big.Int).Neg(z))
|
|
tmp2 := ScalarVectorMul(sL, x)
|
|
return VectorAdd(tmp1, tmp2)
|
|
}
|
|
|
|
func CalculateR(aR, sR, y, po2 []*big.Int, z, x *big.Int) []*big.Int {
|
|
if len(aR) != len(sR) || len(aR) != len(y) || len(y) != len(po2) {
|
|
log.Info("CalculateR: Arrays not of the same length")
|
|
}
|
|
|
|
z2 := new(big.Int).Exp(z, big.NewInt(2), EC.N)
|
|
tmp11 := VectorAddScalar(aR, z)
|
|
tmp12 := ScalarVectorMul(sR, x)
|
|
tmp1 := VectorHadamard(y, VectorAdd(tmp11, tmp12))
|
|
tmp2 := ScalarVectorMul(po2, z2)
|
|
|
|
return VectorAdd(tmp1, tmp2)
|
|
}
|
|
|
|
// Calculates (aL - z*1^n) + sL*x
|
|
func CalculateLMRP(aL, sL []*big.Int, z, x *big.Int) []*big.Int {
|
|
tmp1 := VectorAddScalar(aL, new(big.Int).Neg(z))
|
|
tmp2 := ScalarVectorMul(sL, x)
|
|
return VectorAdd(tmp1, tmp2)
|
|
}
|
|
|
|
func CalculateRMRP(aR, sR, y, zTimesTwo []*big.Int, z, x *big.Int) []*big.Int {
|
|
if len(aR) != len(sR) || len(aR) != len(y) || len(y) != len(zTimesTwo) {
|
|
log.Info("CalculateRMRP: Arrays not of the same length")
|
|
}
|
|
|
|
tmp11 := VectorAddScalar(aR, z)
|
|
tmp12 := ScalarVectorMul(sR, x)
|
|
tmp1 := VectorHadamard(y, VectorAdd(tmp11, tmp12))
|
|
|
|
return VectorAdd(tmp1, zTimesTwo)
|
|
}
|
|
|
|
/*
|
|
DeltaMRP is a helper function that is used in the multi range proof
|
|
\delta(y, z) = (z-z^2)<1^n, y^n> - \sum_j z^3+j<1^n, 2^n>
|
|
*/
|
|
|
|
func DeltaMRP(y []*big.Int, z *big.Int, m int) *big.Int {
|
|
// (z-z^2)<1^n, y^n>
|
|
z2 := new(big.Int).Mod(new(big.Int).Mul(z, z), EC.N)
|
|
t1 := new(big.Int).Mod(new(big.Int).Sub(z, z2), EC.N)
|
|
t2 := new(big.Int).Mod(new(big.Int).Mul(t1, VectorSum(y)), EC.N)
|
|
|
|
// \sum_j z^3+j<1^n, 2^n>
|
|
// <1^n, 2^n> = 2^n - 1
|
|
po2sum := new(big.Int).Sub(
|
|
new(big.Int).Exp(
|
|
big.NewInt(2), big.NewInt(int64(EC.V/m)), EC.N), big.NewInt(1))
|
|
t3 := big.NewInt(0)
|
|
|
|
for j := 0; j < m; j++ {
|
|
zp := new(big.Int).Exp(z, big.NewInt(3+int64(j)), EC.N)
|
|
tmp1 := new(big.Int).Mod(new(big.Int).Mul(zp, po2sum), EC.N)
|
|
t3 = new(big.Int).Mod(new(big.Int).Add(t3, tmp1), EC.N)
|
|
}
|
|
|
|
return new(big.Int).Mod(new(big.Int).Sub(t2, t3), EC.N)
|
|
}
|
|
|
|
type MultiRangeProof struct {
|
|
Comms []ECPoint
|
|
A ECPoint
|
|
S ECPoint
|
|
T1 ECPoint
|
|
T2 ECPoint
|
|
Tau *big.Int
|
|
Th *big.Int
|
|
Mu *big.Int
|
|
IPP InnerProdArg
|
|
|
|
// challenges
|
|
Cy *big.Int
|
|
Cz *big.Int
|
|
Cx *big.Int
|
|
}
|
|
|
|
func serializePointArray(pa []ECPoint, serializeSize bool) []byte {
|
|
ret := []byte{}
|
|
|
|
if serializeSize {
|
|
size := make([]byte, 4)
|
|
binary.BigEndian.PutUint32(size, uint32(len(pa)))
|
|
ret = append(ret, size[:]...)
|
|
}
|
|
|
|
for i := 0; i < len(pa); i++ {
|
|
sp := SerializeCompressed(pa[i].toECPubKey())
|
|
ret = append(ret, sp[:]...)
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func deserializePointArray(input []byte, numPoint uint32) ([]ECPoint, error) {
|
|
if len(input) <= 4 {
|
|
return []ECPoint{}, errors.New("input data invalid")
|
|
}
|
|
numPointSize := uint32(0)
|
|
if numPoint == 0 {
|
|
numPointSize = 4
|
|
numPoint = binary.BigEndian.Uint32(input[0:4])
|
|
}
|
|
if uint32(len(input)) < (numPointSize + 33*numPoint) {
|
|
return []ECPoint{}, errors.New("input data too short")
|
|
}
|
|
ret := make([]ECPoint, numPoint)
|
|
offset := numPointSize
|
|
for i := 0; i < int(numPoint); i++ {
|
|
compressed := DeserializeCompressed(curve, input[offset:offset+33])
|
|
if compressed == nil {
|
|
return ret, errors.New("invalid input data")
|
|
}
|
|
ret[i] = *toECPoint(compressed)
|
|
offset += 33
|
|
}
|
|
return ret, nil
|
|
}
|
|
|
|
func (ipp *InnerProdArg) Serialize() []byte {
|
|
proof := []byte{}
|
|
|
|
spa := serializePointArray(ipp.L, false)
|
|
proof = append(proof, spa[:]...)
|
|
|
|
spa = serializePointArray(ipp.R, false)
|
|
proof = append(proof, spa[:]...)
|
|
|
|
if ipp.A.Sign() < 0 {
|
|
ipp.A.Mod(ipp.A, EC.N)
|
|
}
|
|
sp := PadTo32Bytes(ipp.A.Bytes())
|
|
proof = append(proof, sp[:]...)
|
|
|
|
sp = PadTo32Bytes(ipp.B.Bytes())
|
|
proof = append(proof, sp[:]...)
|
|
|
|
for i := 0; i < len(ipp.Challenges); i++ {
|
|
sp = PadTo32Bytes(ipp.Challenges[i].Bytes())
|
|
proof = append(proof, sp[:]...)
|
|
}
|
|
|
|
return proof
|
|
}
|
|
|
|
func (ipp *InnerProdArg) Deserialize(proof []byte, numChallenges int) error {
|
|
if len(proof) <= 12 {
|
|
return errors.New("proof data too short")
|
|
}
|
|
offset := 0
|
|
L, err := deserializePointArray(proof[:], uint32(numChallenges)-1)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ipp.L = append(ipp.L, L[:]...)
|
|
offset += len(L) * 33
|
|
|
|
R, err := deserializePointArray(proof[offset:], uint32(numChallenges)-1)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
ipp.R = append(ipp.R, R[:]...)
|
|
offset += len(R) * 33
|
|
|
|
if len(proof) <= offset+64+4 {
|
|
return errors.New("proof data too short")
|
|
}
|
|
|
|
ipp.A = new(big.Int).SetBytes(proof[offset : offset+32])
|
|
offset += 32
|
|
ipp.B = new(big.Int).SetBytes(proof[offset : offset+32])
|
|
offset += 32
|
|
|
|
if len(proof) <= (offset + 32*numChallenges) {
|
|
return errors.New("input data too short")
|
|
}
|
|
for i := 0; i < numChallenges; i++ {
|
|
ipp.Challenges = append(ipp.Challenges, new(big.Int).SetBytes(proof[offset:offset+32]))
|
|
offset += 32
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (mrp *MultiRangeProof) Serialize() []byte {
|
|
proof := []byte{}
|
|
|
|
serializedPA := serializePointArray(mrp.Comms, true)
|
|
proof = append(proof, serializedPA[:]...)
|
|
|
|
sp := SerializeCompressed(mrp.A.toECPubKey())
|
|
proof = append(proof, sp[:]...)
|
|
|
|
sp = SerializeCompressed(mrp.S.toECPubKey())
|
|
proof = append(proof, sp[:]...)
|
|
|
|
sp = SerializeCompressed(mrp.T1.toECPubKey())
|
|
proof = append(proof, sp[:]...)
|
|
|
|
sp = SerializeCompressed(mrp.T2.toECPubKey())
|
|
proof = append(proof, sp[:]...)
|
|
|
|
//Tau, Th, Mu
|
|
sp = PadTo32Bytes(mrp.Tau.Bytes())
|
|
proof = append(proof, sp[:]...)
|
|
|
|
if mrp.Th.Sign() < 0 {
|
|
mrp.Th.Mod(mrp.Th, EC.N)
|
|
}
|
|
sp = PadTo32Bytes(mrp.Th.Bytes())
|
|
proof = append(proof, sp[:]...)
|
|
|
|
sp = PadTo32Bytes(mrp.Mu.Bytes())
|
|
proof = append(proof, sp[:]...)
|
|
|
|
//challenges
|
|
sp = mrp.IPP.Serialize()
|
|
proof = append(proof, sp[:]...)
|
|
|
|
//challenges
|
|
sp = PadTo32Bytes(mrp.Cy.Bytes())
|
|
proof = append(proof, sp[:]...)
|
|
|
|
sp = PadTo32Bytes(mrp.Cz.Bytes())
|
|
proof = append(proof, sp[:]...)
|
|
|
|
sp = PadTo32Bytes(mrp.Cx.Bytes())
|
|
proof = append(proof, sp[:]...)
|
|
|
|
return proof
|
|
}
|
|
|
|
func (mrp *MultiRangeProof) Deserialize(proof []byte) error {
|
|
Cs, err := deserializePointArray(proof[:], 0)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
mrp.Comms = append(mrp.Comms, Cs[:]...)
|
|
|
|
offset := 4 + len(Cs)*33
|
|
|
|
if len(proof) <= offset+4+4*33+6*32 {
|
|
return errors.New("invalid input data")
|
|
}
|
|
compressed := DeserializeCompressed(curve, proof[offset:offset+33])
|
|
if compressed == nil {
|
|
return errors.New("failed to decode A")
|
|
}
|
|
offset += 33
|
|
mrp.A = *toECPoint(compressed)
|
|
|
|
compressed = DeserializeCompressed(curve, proof[offset:offset+33])
|
|
if compressed == nil {
|
|
return errors.New("failed to decode S")
|
|
}
|
|
offset += 33
|
|
mrp.S = *toECPoint(compressed)
|
|
|
|
compressed = DeserializeCompressed(curve, proof[offset:offset+33])
|
|
if compressed == nil {
|
|
return errors.New("failed to decode T2")
|
|
}
|
|
offset += 33
|
|
mrp.T1 = *toECPoint(compressed)
|
|
|
|
compressed = DeserializeCompressed(curve, proof[offset:offset+33])
|
|
if compressed == nil {
|
|
return errors.New("failed to decode T2")
|
|
}
|
|
offset += 33
|
|
mrp.T2 = *toECPoint(compressed)
|
|
|
|
mrp.Tau = new(big.Int).SetBytes(proof[offset : offset+32])
|
|
offset += 32
|
|
|
|
mrp.Th = new(big.Int).SetBytes(proof[offset : offset+32])
|
|
offset += 32
|
|
|
|
mrp.Mu = new(big.Int).SetBytes(proof[offset : offset+32])
|
|
offset += 32
|
|
|
|
numChallenges := int(math.Log2(float64(len(mrp.Comms)*bitsPerValue))) + 1
|
|
mrp.IPP.Deserialize(proof[offset:], numChallenges)
|
|
offset += len(mrp.IPP.L)*33 + len(mrp.IPP.R)*33 + len(mrp.IPP.Challenges)*32 + 2*32
|
|
|
|
mrp.Cy = new(big.Int).SetBytes(proof[offset : offset+32])
|
|
offset += 32
|
|
|
|
mrp.Cz = new(big.Int).SetBytes(proof[offset : offset+32])
|
|
offset += 32
|
|
|
|
mrp.Cx = new(big.Int).SetBytes(proof[offset : offset+32])
|
|
|
|
return nil
|
|
}
|
|
|
|
func pedersenCommitment(gamma *big.Int, value *big.Int) ECPoint {
|
|
return EC.G.Mult(value).Add(EC.H.Mult(gamma))
|
|
}
|
|
|
|
var MAX_64_BITS = new(big.Int).SetUint64(0xFFFFFFFFFFFFFFFF)
|
|
|
|
/*
|
|
MultiRangeProof Prove
|
|
Takes in a list of values and provides an aggregate
|
|
range proof for all the values.
|
|
changes:
|
|
|
|
all values are concatenated
|
|
r(x) is computed differently
|
|
tau_x calculation is different
|
|
delta calculation is different
|
|
|
|
{(g, h \in G, \textbf{V} \in G^m ; \textbf{v, \gamma} \in Z_p^m) :
|
|
|
|
V_j = h^{\gamma_j}g^{v_j} \wedge v_j \in [0, 2^n - 1] \forall j \in [1, m]}
|
|
*/
|
|
var bitsPerValue = 64
|
|
|
|
func MRPProve(values []*big.Int) (MultiRangeProof, error) {
|
|
var acceptedInputNumber bool
|
|
|
|
MRPResult := MultiRangeProof{}
|
|
|
|
m := len(values)
|
|
|
|
if m == 1 || m == 2 || m == 4 || m == 8 {
|
|
acceptedInputNumber = true
|
|
}
|
|
|
|
if !acceptedInputNumber {
|
|
return MultiRangeProof{}, errors.New("value number is not supported - just 1, 2, 4, 8")
|
|
}
|
|
|
|
EC = genECPrimeGroupKey(m * bitsPerValue)
|
|
|
|
// we concatenate the binary representation of the values
|
|
|
|
PowerOfTwos := PowerVector(bitsPerValue, big.NewInt(2))
|
|
|
|
Comms := make([]ECPoint, m)
|
|
gammas := make([]*big.Int, m)
|
|
aLConcat := make([]*big.Int, EC.V)
|
|
aRConcat := make([]*big.Int, EC.V)
|
|
|
|
for j := range values {
|
|
v := values[j]
|
|
if v.Sign() == -1 {
|
|
return MultiRangeProof{}, errors.New("value is below range! Not proving")
|
|
}
|
|
|
|
if v.Cmp(MAX_64_BITS) == 1 {
|
|
return MultiRangeProof{}, errors.New("value is above range! Not proving")
|
|
}
|
|
|
|
if v.Cmp(new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(bitsPerValue)), EC.N)) == 1 {
|
|
return MultiRangeProof{}, errors.New("value is above range! Not proving")
|
|
}
|
|
|
|
gamma, err := rand.Int(rand.Reader, EC.N)
|
|
|
|
check(err)
|
|
Comms[j] = pedersenCommitment(gamma, v)
|
|
gammas[j] = gamma
|
|
|
|
// break up v into its bitwise representation
|
|
aL := reverse(StrToBigIntArray(PadLeft(fmt.Sprintf("%b", v), "0", bitsPerValue)))
|
|
aR := VectorAddScalar(aL, big.NewInt(-1))
|
|
|
|
for i := range aR {
|
|
aLConcat[bitsPerValue*j+i] = aL[i]
|
|
aRConcat[bitsPerValue*j+i] = aR[i]
|
|
}
|
|
}
|
|
|
|
//compare aL, aR
|
|
MRPResult.Comms = Comms
|
|
|
|
alpha, err := rand.Int(rand.Reader, EC.N)
|
|
check(err)
|
|
|
|
A := TwoVectorPCommitWithGens(EC.BPG, EC.BPH, aLConcat, aRConcat).Add(EC.H.Mult(alpha))
|
|
MRPResult.A = A
|
|
|
|
// fmt.Println("Ec.V %+v", EC.V)
|
|
sL := RandVector(EC.V)
|
|
sR := RandVector(EC.V)
|
|
|
|
rho, err := rand.Int(rand.Reader, EC.N)
|
|
check(err)
|
|
|
|
S := TwoVectorPCommitWithGens(EC.BPG, EC.BPH, sL, sR).Add(EC.H.Mult(rho))
|
|
MRPResult.S = S
|
|
|
|
// input := append(PadTo32Bytes(A.X.Bytes()), PadTo32Bytes(A.Y.Bytes())...)
|
|
// chal1s256 := crypto.Keccak256(input)
|
|
chal1s256 := HashPointsToBytes(append(Comms, A))
|
|
|
|
// chal1s256 := sha256.Sum256([]byte(A.X.String() + A.Y.String()))
|
|
cy := new(big.Int).SetBytes(chal1s256[:])
|
|
MRPResult.Cy = cy
|
|
|
|
// input = append(PadTo32Bytes(S.X.Bytes()), PadTo32Bytes(S.Y.Bytes())...)
|
|
// chal2s256 := crypto.Keccak256(input)
|
|
chal2s256 := HashPointsToBytes(append(Comms, A, S))
|
|
|
|
// chal2s256 := sha256.Sum256([]byte(S.X.String() + S.Y.String()))
|
|
cz := new(big.Int).SetBytes(chal2s256[:])
|
|
MRPResult.Cz = cz
|
|
|
|
zPowersTimesTwoVec := make([]*big.Int, EC.V)
|
|
for j := 0; j < m; j++ {
|
|
zp := new(big.Int).Exp(cz, big.NewInt(2+int64(j)), EC.N)
|
|
for i := 0; i < bitsPerValue; i++ {
|
|
zPowersTimesTwoVec[j*bitsPerValue+i] = new(big.Int).Mod(new(big.Int).Mul(PowerOfTwos[i], zp), EC.N)
|
|
}
|
|
}
|
|
|
|
PowerOfCY := PowerVector(EC.V, cy)
|
|
// fmt.Println(PowerOfCY)
|
|
l0 := VectorAddScalar(aLConcat, new(big.Int).Neg(cz))
|
|
l1 := sL
|
|
r0 := VectorAdd(
|
|
VectorHadamard(
|
|
PowerOfCY,
|
|
VectorAddScalar(aRConcat, cz)),
|
|
zPowersTimesTwoVec)
|
|
r1 := VectorHadamard(sR, PowerOfCY)
|
|
|
|
//calculate t0
|
|
vz2 := big.NewInt(0)
|
|
z2 := new(big.Int).Mod(new(big.Int).Mul(cz, cz), EC.N)
|
|
PowerOfCZ := PowerVector(m, cz)
|
|
for j := 0; j < m; j++ {
|
|
vz2 = new(big.Int).Add(vz2,
|
|
new(big.Int).Mul(
|
|
PowerOfCZ[j],
|
|
new(big.Int).Mul(values[j], z2)))
|
|
vz2 = new(big.Int).Mod(vz2, EC.N)
|
|
}
|
|
|
|
t0 := new(big.Int).Mod(new(big.Int).Add(vz2, DeltaMRP(PowerOfCY, cz, m)), EC.N)
|
|
|
|
t1 := new(big.Int).Mod(new(big.Int).Add(InnerProduct(l1, r0), InnerProduct(l0, r1)), EC.N)
|
|
t2 := InnerProduct(l1, r1)
|
|
|
|
// given the t_i values, we can generate commitments to them
|
|
tau1, err := rand.Int(rand.Reader, EC.N)
|
|
check(err)
|
|
tau2, err := rand.Int(rand.Reader, EC.N)
|
|
check(err)
|
|
|
|
T1 := pedersenCommitment(tau1, t1) // EC.G.Mult(t1).Add(EC.H.Mult(tau1)) //commitment to t1
|
|
T2 := pedersenCommitment(tau2, t2) //EC.G.Mult(t2).Add(EC.H.Mult(tau2)) //commitment to t2
|
|
|
|
MRPResult.T1 = T1
|
|
MRPResult.T2 = T2
|
|
|
|
// t1Byte := append(PadTo32Bytes(T1.X.Bytes()), PadTo32Bytes(T1.Y.Bytes())...)
|
|
// t2Byte := append(PadTo32Bytes(T2.X.Bytes()), PadTo32Bytes(T2.Y.Bytes())...)
|
|
// input = append(t1Byte, t2Byte...)
|
|
// chal3s256 := crypto.Keccak256(input)
|
|
chal3s256 := HashPointsToBytes(append(Comms, A, S, T1, T2))
|
|
|
|
// chal3s256 := sha256.Sum256([]byte(T1.X.String() + T1.Y.String() + T2.X.String() + T2.Y.String()))
|
|
cx := new(big.Int).SetBytes(chal3s256[:])
|
|
|
|
MRPResult.Cx = cx
|
|
|
|
left := CalculateLMRP(aLConcat, sL, cz, cx)
|
|
right := CalculateRMRP(aRConcat, sR, PowerOfCY, zPowersTimesTwoVec, cz, cx)
|
|
|
|
thatPrime := new(big.Int).Mod( // t0 + t1*x + t2*x^2
|
|
new(big.Int).Add(t0, new(big.Int).Add(new(big.Int).Mul(t1, cx), new(big.Int).Mul(new(big.Int).Mul(cx, cx), t2))), EC.N)
|
|
|
|
that := InnerProduct(left, right) // NOTE: BP Java implementation calculates this from the t_i
|
|
|
|
// thatPrime and that should be equal
|
|
if thatPrime.Cmp(that) != 0 {
|
|
fmt.Println("Proving -- Uh oh! Two diff ways to compute same value not working")
|
|
fmt.Printf("\tthatPrime = %s\n", thatPrime.String())
|
|
fmt.Printf("\tthat = %s \n", that.String())
|
|
}
|
|
|
|
MRPResult.Th = that
|
|
|
|
vecRandomnessTotal := big.NewInt(0)
|
|
for j := 0; j < m; j++ {
|
|
zp := new(big.Int).Exp(cz, big.NewInt(2+int64(j)), EC.N)
|
|
tmp1 := new(big.Int).Mul(gammas[j], zp)
|
|
vecRandomnessTotal = new(big.Int).Mod(new(big.Int).Add(vecRandomnessTotal, tmp1), EC.N)
|
|
}
|
|
//fmt.Println(vecRandomnessTotal)
|
|
taux1 := new(big.Int).Mod(new(big.Int).Mul(tau2, new(big.Int).Mul(cx, cx)), EC.N)
|
|
taux2 := new(big.Int).Mod(new(big.Int).Mul(tau1, cx), EC.N)
|
|
taux := new(big.Int).Mod(new(big.Int).Add(taux1, new(big.Int).Add(taux2, vecRandomnessTotal)), EC.N)
|
|
|
|
MRPResult.Tau = taux
|
|
|
|
mu := new(big.Int).Mod(new(big.Int).Add(alpha, new(big.Int).Mul(rho, cx)), EC.N)
|
|
MRPResult.Mu = mu
|
|
|
|
HPrime := make([]ECPoint, len(EC.BPH))
|
|
|
|
for i := range HPrime {
|
|
HPrime[i] = EC.BPH[i].Mult(new(big.Int).ModInverse(PowerOfCY[i], EC.N))
|
|
}
|
|
|
|
P := TwoVectorPCommitWithGens(EC.BPG, HPrime, left, right)
|
|
//fmt.Println(P)
|
|
|
|
MRPResult.IPP = InnerProductProve(left, right, that, P, EC.U, EC.BPG, HPrime)
|
|
|
|
return MRPResult, nil
|
|
}
|
|
|
|
/*
|
|
MultiRangeProof Verify
|
|
Takes in a MultiRangeProof and verifies its correctness
|
|
*/
|
|
func MRPVerify(mrp *MultiRangeProof) bool {
|
|
m := len(mrp.Comms)
|
|
EC = genECPrimeGroupKey(m * bitsPerValue)
|
|
|
|
//changes:
|
|
// check 1 changes since it includes all commitments
|
|
// check 2 commitment generation is also different
|
|
|
|
// verify the challenges
|
|
// input := append(PadTo32Bytes(mrp.A.X.Bytes()), PadTo32Bytes(mrp.A.Y.Bytes())...)
|
|
// chal1s256 := crypto.Keccak256(input)
|
|
chal1s256 := HashPointsToBytes(append(mrp.Comms, mrp.A))
|
|
|
|
cy := new(big.Int).SetBytes(chal1s256[:])
|
|
|
|
if cy.Cmp(mrp.Cy) != 0 {
|
|
log.Debug("MRPVerify challenge failed!", "Cy", common.Bytes2Hex(mrp.Cy.Bytes()))
|
|
return false
|
|
}
|
|
|
|
// input = append(PadTo32Bytes(mrp.S.X.Bytes()), PadTo32Bytes(mrp.S.Y.Bytes())...)
|
|
// chal2s256 := crypto.Keccak256(input)
|
|
chal2s256 := HashPointsToBytes(append(mrp.Comms, mrp.A, mrp.S))
|
|
|
|
// chal2s256 := sha256.Sum256([]byte(mrp.S.X.String() + mrp.S.Y.String()))
|
|
cz := new(big.Int).SetBytes(chal2s256[:])
|
|
if cz.Cmp(mrp.Cz) != 0 {
|
|
log.Debug("MRPVerify challenge failed!", "Cz", common.Bytes2Hex(mrp.Cz.Bytes()))
|
|
return false
|
|
}
|
|
|
|
// t1Byte := append(PadTo32Bytes(mrp.T1.X.Bytes()), PadTo32Bytes(mrp.T1.Y.Bytes())...)
|
|
// t2Byte := append(PadTo32Bytes(mrp.T2.X.Bytes()), PadTo32Bytes(mrp.T2.Y.Bytes())...)
|
|
// input = append(t1Byte, t2Byte...)
|
|
// chal3s256 := crypto.Keccak256(input)
|
|
chal3s256 := HashPointsToBytes(append(mrp.Comms, mrp.A, mrp.S, mrp.T1, mrp.T2))
|
|
|
|
// chal3s256 := sha256.Sum256([]byte(T1.X.String() + T1.Y.String() + T2.X.String() + T2.Y.String()))
|
|
// cx := new(big.Int).SetBytes(chal3s256[:])
|
|
//chal3s256 := sha256.Sum256([]byte(mrp.T1.X.String() + mrp.T1.Y.String() + mrp.T2.X.String() + mrp.T2.Y.String()))
|
|
|
|
cx := new(big.Int).SetBytes(chal3s256[:])
|
|
|
|
if cx.Cmp(mrp.Cx) != 0 {
|
|
log.Debug("MRPVerify challenge failed!", "Cx", common.Bytes2Hex(mrp.Cx.Bytes()))
|
|
return false
|
|
}
|
|
|
|
// given challenges are correct, very range proof
|
|
PowersOfY := PowerVector(EC.V, cy)
|
|
|
|
// t_hat * G + tau * H
|
|
lhs := pedersenCommitment(mrp.Tau, mrp.Th) //EC.G.Mult(mrp.Th).Add(EC.H.Mult(mrp.Tau))
|
|
|
|
// z^2 * \bold{z}^m \bold{V} + delta(y,z) * G + x * T1 + x^2 * T2
|
|
CommPowers := EC.Zero()
|
|
PowersOfZ := PowerVector(m, cz)
|
|
z2 := new(big.Int).Mod(new(big.Int).Mul(cz, cz), EC.N)
|
|
|
|
for j := 0; j < m; j++ {
|
|
CommPowers = CommPowers.Add(mrp.Comms[j].Mult(new(big.Int).Mul(z2, PowersOfZ[j])))
|
|
}
|
|
|
|
// TODO i need to change how to calculate the commitment here also ?
|
|
// need to compare and double check with privacy-client lib
|
|
rhs := EC.G.Mult(DeltaMRP(PowersOfY, cz, m)).Add(
|
|
mrp.T1.Mult(cx)).Add(
|
|
mrp.T2.Mult(new(big.Int).Mul(cx, cx))).Add(CommPowers)
|
|
|
|
if !lhs.Equal(rhs) {
|
|
log.Debug("Rangeproof failed")
|
|
return false
|
|
}
|
|
|
|
tmp1 := EC.Zero()
|
|
zneg := new(big.Int).Mod(new(big.Int).Neg(cz), EC.N)
|
|
for i := range EC.BPG {
|
|
tmp1 = tmp1.Add(EC.BPG[i].Mult(zneg))
|
|
}
|
|
|
|
PowerOfTwos := PowerVector(bitsPerValue, big.NewInt(2))
|
|
tmp2 := EC.Zero()
|
|
// generate h'
|
|
HPrime := make([]ECPoint, len(EC.BPH))
|
|
|
|
for i := range HPrime {
|
|
mi := new(big.Int).ModInverse(PowersOfY[i], EC.N)
|
|
HPrime[i] = EC.BPH[i].Mult(mi)
|
|
}
|
|
|
|
for j := 0; j < m; j++ {
|
|
for i := 0; i < bitsPerValue; i++ {
|
|
val1 := new(big.Int).Mul(cz, PowersOfY[j*bitsPerValue+i])
|
|
zp := new(big.Int).Exp(cz, big.NewInt(2+int64(j)), EC.N)
|
|
val2 := new(big.Int).Mod(new(big.Int).Mul(zp, PowerOfTwos[i]), EC.N)
|
|
tmp2 = tmp2.Add(HPrime[j*bitsPerValue+i].Mult(new(big.Int).Add(val1, val2)))
|
|
}
|
|
}
|
|
|
|
// without subtracting this value should equal muCH + l[i]G[i] + r[i]H'[i]
|
|
// we want to make sure that the innerproduct checks out, so we subtract it
|
|
P := mrp.A.Add(mrp.S.Mult(cx)).Add(tmp1).Add(tmp2).Add(EC.H.Mult(mrp.Mu).Neg())
|
|
//fmt.Println(P)
|
|
|
|
if !InnerProductVerifyFast(mrp.Th, P, EC.U, EC.BPG, HPrime, mrp.IPP) {
|
|
log.Debug("Range proof failed!")
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// NewECPrimeGroupKey returns the curve (field),
|
|
// Generator 1 x&y, Generator 2 x&y, order of the generators
|
|
func NewECPrimeGroupKey(n int) CryptoParams {
|
|
curValue := btcec.S256().Gx
|
|
s256 := sha256.New()
|
|
gen1Vals := make([]ECPoint, n)
|
|
gen2Vals := make([]ECPoint, n)
|
|
u := ECPoint{big.NewInt(0), big.NewInt(0)}
|
|
cg := ECPoint{}
|
|
ch := ECPoint{}
|
|
|
|
j := 0
|
|
confirmed := 0
|
|
for confirmed < (2*n + 3) {
|
|
s256.Write(new(big.Int).Add(curValue, big.NewInt(int64(j))).Bytes())
|
|
|
|
potentialXValue := make([]byte, 33)
|
|
binary.LittleEndian.PutUint32(potentialXValue, 2)
|
|
for i, elem := range s256.Sum(nil) {
|
|
potentialXValue[i+1] = elem
|
|
}
|
|
|
|
gen2, err := btcec.ParsePubKey(potentialXValue)
|
|
if err == nil {
|
|
if confirmed == 2*n { // once we've generated all g and h values then assign this to u
|
|
u = ECPoint{gen2.X(), gen2.Y()}
|
|
//fmt.Println("Got that U value")
|
|
} else if confirmed == 2*n+1 {
|
|
cg = ECPoint{gen2.X(), gen2.Y()}
|
|
} else if confirmed == 2*n+2 {
|
|
ch = ECPoint{gen2.X(), gen2.Y()}
|
|
} else {
|
|
if confirmed%2 == 0 {
|
|
gen1Vals[confirmed/2] = ECPoint{gen2.X(), gen2.Y()}
|
|
//fmt.Println("new G Value")
|
|
} else {
|
|
gen2Vals[confirmed/2] = ECPoint{gen2.X(), gen2.Y()}
|
|
//fmt.Println("new H value")
|
|
}
|
|
}
|
|
confirmed += 1
|
|
}
|
|
j += 1
|
|
}
|
|
|
|
return CryptoParams{
|
|
btcec.S256(),
|
|
btcec.S256(),
|
|
gen1Vals,
|
|
gen2Vals,
|
|
btcec.S256().N,
|
|
u,
|
|
n,
|
|
cg,
|
|
ch}
|
|
}
|
|
|
|
func genECPrimeGroupKey(n int) CryptoParams {
|
|
// curValue := btcec.S256().Gx
|
|
// s256 := sha256.New()
|
|
gen1Vals := make([]ECPoint, n)
|
|
gen2Vals := make([]ECPoint, n)
|
|
// u := ECPoint{big.NewInt(0), big.NewInt(0)}
|
|
hx, _ := new(big.Int).SetString("50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0", 16)
|
|
hy, _ := new(big.Int).SetString("31d3c6863973926e049e637cb1b5f40a36dac28af1766968c30c2313f3a38904", 16)
|
|
ch := ECPoint{hx, hy}
|
|
|
|
gx, _ := new(big.Int).SetString("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", 16)
|
|
gy, _ := new(big.Int).SetString("483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", 16)
|
|
cg := ECPoint{gx, gy}
|
|
|
|
i := 0
|
|
for i < n {
|
|
gen2Vals[i] = ch.Mult(
|
|
big.NewInt(int64(i*2 + 1)),
|
|
)
|
|
gen1Vals[i] = cg.Mult(
|
|
big.NewInt(int64(i*2 + 2)),
|
|
)
|
|
i++
|
|
}
|
|
|
|
u := cg.Mult(
|
|
big.NewInt(int64(n + 3)),
|
|
)
|
|
|
|
return CryptoParams{
|
|
btcec.S256(),
|
|
btcec.S256(),
|
|
gen1Vals,
|
|
gen2Vals,
|
|
btcec.S256().N,
|
|
u,
|
|
n,
|
|
ch,
|
|
cg}
|
|
}
|
|
|
|
func init() {
|
|
// just need the base parameter N, P, G, H for this init, ignore everything else
|
|
EC = CryptoParams{
|
|
btcec.S256(),
|
|
btcec.S256(),
|
|
make([]ECPoint, VecLength),
|
|
make([]ECPoint, VecLength),
|
|
btcec.S256().N,
|
|
ECPoint{big.NewInt(0), big.NewInt(0)},
|
|
VecLength,
|
|
ECPoint{big.NewInt(0), big.NewInt(0)},
|
|
ECPoint{big.NewInt(0), big.NewInt(0)}}
|
|
}
|