145 lines
4.0 KiB
Go
145 lines
4.0 KiB
Go
package zkp
|
|
|
|
import (
|
|
"crypto/ecdsa"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"math/big"
|
|
"strings"
|
|
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
"qoobing.com/gomod/log"
|
|
)
|
|
|
|
type DLogProof struct {
|
|
ChallengeResponse *big_Int `json:"cr"`
|
|
RandomPoint string `json:"pkr"`
|
|
}
|
|
|
|
func (dlogproof *DLogProof) ToString() string {
|
|
var b, _ = json.Marshal(dlogproof)
|
|
return string(b)
|
|
}
|
|
|
|
func DLogProofFromString(jsonstr string) (*DLogProof, error) {
|
|
var proof = DLogProof{}
|
|
if err := json.Unmarshal([]byte(jsonstr), &proof); err != nil {
|
|
return nil, err
|
|
}
|
|
return &proof, nil
|
|
}
|
|
|
|
/*
|
|
* Prove:
|
|
* step 1. generate random bignumber: skr, let pkr = skr * G
|
|
* step 2. caculate challenge: c = SHA256(pkr || G || pk)
|
|
* step 3. caculate challenge response: cr = skr - c * sk
|
|
* result:
|
|
* (pkr, cr)
|
|
*/
|
|
func DLogProve(sk *big.Int) (proof *DLogProof, err error) {
|
|
// Step 0. get pk
|
|
cv := crypto.S256()
|
|
Gx := cv.Params().Gx
|
|
Gy := cv.Params().Gy
|
|
x, y := cv.ScalarBaseMult(sk.Bytes())
|
|
var pk = ecdsa.PublicKey{Curve: cv, X: x, Y: y}
|
|
|
|
// Step 1. generate random bignumber: skr, let pkr = skr * G
|
|
randomkey, err := crypto.GenerateKey()
|
|
if err != nil {
|
|
log.Warningf("Gernerate random Q1 failed: '%s'", err.Error())
|
|
return nil, errors.New("generate random key/number failed")
|
|
}
|
|
var skr = randomkey.D
|
|
var pkr = randomkey.PublicKey
|
|
//TODO: sk_t_rand_commitment.zeroize();
|
|
|
|
// Step 2. caculate challenge: c = SHA256(pkr || G || pk)
|
|
challenge := fmt.Sprintf(
|
|
"%064x,%064x@%064x,%064x@%064x,%064x",
|
|
pkr.X, pkr.Y, Gx, Gy, pk.X, pk.Y)
|
|
chash256 := sha256.Sum256([]byte(challenge))
|
|
var c = new(big.Int).SetBytes(chash256[:])
|
|
log.Debugf("challenge='%s',c='%x'", challenge, c)
|
|
|
|
// Step 3. caculate challenge response: cr = skr - c * sk
|
|
cvN := cv.Params().N
|
|
tmp := new(big.Int).Mul(c, sk)
|
|
var cr = new(big.Int).Sub(skr, tmp)
|
|
cr = new(big.Int).Mod(cr, cvN)
|
|
|
|
// return
|
|
proof = &DLogProof{
|
|
RandomPoint: fmt.Sprintf("%064x,%064x", pkr.X, pkr.Y),
|
|
ChallengeResponse: (*big_Int)(cr),
|
|
}
|
|
return proof, nil
|
|
}
|
|
|
|
/*
|
|
* Verify:
|
|
* step 1. caculate challenge: c = SHA256(pkr || G || pk)
|
|
* step 2. caculate proof verify: pkv = cr * G + c * pk
|
|
* result:
|
|
* pkr =?= pkv
|
|
*/
|
|
func DLogVerify(pkstr string, proof *DLogProof) bool {
|
|
// Step 0. get pk & pkr
|
|
var pk, err1 = HexStringToS256Point(pkstr)
|
|
if err1 != nil {
|
|
log.Infof("input pk is invalid: %s, pk=[%s]", err1, pkstr)
|
|
return false
|
|
}
|
|
var pkr, err2 = HexStringToS256Point(proof.RandomPoint)
|
|
if err2 != nil {
|
|
log.Infof("input pkr is invalid: %s, pkr=[%s]", err2, proof.RandomPoint)
|
|
return false
|
|
}
|
|
|
|
// Step 1. caculate challenge: c = SHA256(pkr || G || pk)
|
|
cv := crypto.S256()
|
|
Gx := cv.Params().Gx
|
|
Gy := cv.Params().Gy
|
|
challenge := fmt.Sprintf(
|
|
"%064x,%064x@%064x,%064x@%064x,%064x",
|
|
pkr.X, pkr.Y, Gx, Gy, pk.X, pk.Y)
|
|
chash256 := sha256.Sum256([]byte(challenge))
|
|
var c = new(big.Int).SetBytes(chash256[:])
|
|
var cr = (*big.Int)(proof.ChallengeResponse)
|
|
log.Debugf("challenge='%s',c='%x',cr='%x'", challenge, c, cr)
|
|
|
|
// Step 2. caculate proof verify: pkv = cr * G + c * pk
|
|
var pkv = ecdsa.PublicKey{Curve: crypto.S256()}
|
|
pkv.X, pkv.Y = cv.ScalarBaseMult(cr.Bytes())
|
|
tempX, tempY := cv.ScalarMult(pk.X, pk.Y, c.Bytes())
|
|
tempX, tempY = cv.Add(pkv.X, pkv.Y, tempX, tempY)
|
|
log.Debugf("pkv='%x,%x'", tempX, tempY)
|
|
|
|
// return
|
|
if pkr.X.Cmp(tempX) != 0 || pkr.Y.Cmp(tempY) != 0 {
|
|
log.Debugf("pkr='%x,%x'", pkr.X, pkr.Y)
|
|
log.Debugf("pkv='%x,%x'", tempX, tempY)
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func HexStringToS256Point(pstr string) (*ecdsa.PublicKey, error) {
|
|
var pk = ecdsa.PublicKey{Curve: crypto.S256()}
|
|
if x2y2 := strings.Split(pstr, ","); len(x2y2) != 2 {
|
|
return nil, errors.New("input point is invalid")
|
|
} else if x, err := hex.DecodeString(x2y2[0]); err != nil {
|
|
return nil, fmt.Errorf("input point.x is invalid: [%s]", err)
|
|
} else if y, err := hex.DecodeString(x2y2[1]); err != nil {
|
|
return nil, fmt.Errorf("input point.y is invalid: [%s]", err)
|
|
} else {
|
|
pk.X = new(big.Int).SetBytes(x)
|
|
pk.Y = new(big.Int).SetBytes(y)
|
|
}
|
|
return &pk, nil
|
|
}
|