commit a557a59926f812222103196db2cdb6b46992ab57 Author: bryanqiu Date: Fri Nov 11 16:09:13 2022 +0800 initial version diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..42e6b40 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module qoobing.com/gomod/zkp + +go 1.19 diff --git a/zkp.go b/zkp.go new file mode 100644 index 0000000..920d56c --- /dev/null +++ b/zkp.go @@ -0,0 +1,119 @@ +package zkp + +import ( + "crypto/ecdsa" + "crypto/sha256" + "encoding/hex" + "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"` +} + +/* + * 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 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( + "%x,%x@%x,%x@%x,%x", pkr.X, pkr.Y, Gx, Gy, pk.X, pk.Y) + var c = new(big.Int).SetBytes(sha256.Sum256([]byte(challenge))[:]) + + // Step 3. caculate challenge response: cr = skr - c * sk + tmp := new(big.Int).Mul(c, sk) + var cr = new(big.Int).Mul(skr) + + // return + proof = &DLogProof{ + RandomPoint: fmt.Sprintf("%x,%x", pkr.X, pkr.Y), + ChallengeResponse: 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, err = HexStringToS256Point(pkstr) + if err != nil { + //errors.New("input pk is invalid") + return false + } + var pkr, err = HexStringToS256Point(proof.RandomPoint) + if err != nil { + //errors.New("input pkr is invalid") + 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( + "%x,%x@%x,%x@%x,%x", pkr.X, pkr.Y, Gx, Gy, pk.X, pk.Y) + var c = new(big.Int).SetBytes(sha256.Sum256([]byte(challenge))[:]) + var cr = proof.ChallengeResponse + + // 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) + + // return + if pkr.X == tempX && pkr.Y == Y { + return true + } + return false +} + +func HexStringToS256Point(p string) (*ecdsa.PublicKey, error) { + var pk = ecdsa.PublicKey{Curve: crypto.S256()} + if x2y2 := strings.Split(pkstr, ","); len(x2y2) != 2 { + return nil, errors.New("input pk is invalid") + } else if x, err := hex.DecodeString(x2y2[0]); err != nil { + return nil, errors.New("input pk.x is invalid") + } else if y, err := hex.DecodeString(x2y2[1]); err != nil { + return nil, errors.New("input pk.y is invalid") + } else { + pk.X = new(big.Int).SetBytes(x) + pk.Y = new(big.Int).SetBytes(y) + } + return pk, nil +}