├── .gitignore ├── examples └── main.go ├── btcec ├── README.md ├── doc.go ├── privkey.go ├── genprecomps.go ├── precompute.go ├── pubkey.go ├── ciphering.go ├── gensecp256k1.go ├── signature.go └── field_test.go ├── LICENSE ├── inequality.go ├── zksigma.go ├── rangeproof_test.go ├── gspfs_test.go ├── README.md ├── consistency_test.go ├── inequality_test.go ├── equivalence_test.go ├── gspfs.go ├── disjunctive_test.go ├── equivalence.go ├── consistency.go ├── disjunctive.go ├── crypto.go ├── abc_test.go ├── abc.go ├── crypto_test.go ├── wire └── common.go └── rangeproof.go /.gitignore: -------------------------------------------------------------------------------- 1 | examples/main 2 | examples/examples -------------------------------------------------------------------------------- /examples/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/mit-dci/zksigma" 7 | ) 8 | 9 | func main() { 10 | fmt.Println(zksigma.ZKCurve) 11 | } 12 | -------------------------------------------------------------------------------- /btcec/README.md: -------------------------------------------------------------------------------- 1 | btcec 2 | ===== 3 | 4 | This package contains a modified version of [btcec](https://github.com/btcsuite/btcd/tree/master/btcec). It adds ScalarBaseMult with a secondary generator point, required for [zksigma](https://github.com/mit-dci/zksigma) -------------------------------------------------------------------------------- /btcec/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013-2014 The btcsuite developers 2 | // Use of this source code is governed by an ISC 3 | // license that can be found in the LICENSE file. 4 | 5 | /* 6 | Package btcec implements support for the elliptic curves needed for bitcoin. 7 | 8 | Bitcoin uses elliptic curve cryptography using koblitz curves 9 | (specifically secp256k1) for cryptographic functions. See 10 | http://www.secg.org/collateral/sec2_final.pdf for details on the 11 | standard. 12 | 13 | This package provides the data structures and functions implementing the 14 | crypto/elliptic Curve interface in order to permit using these curves 15 | with the standard crypto/ecdsa package provided with go. Helper 16 | functionality is provided to parse signatures and public keys from 17 | standard formats. It was designed for use with btcd, but should be 18 | general enough for other uses of elliptic curve crypto. It was originally based 19 | on some initial work by ThePiachu, but has significantly diverged since then. 20 | */ 21 | package btcec 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 The MIT Digital Currency Initiative @ Media Lab 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /inequality.go: -------------------------------------------------------------------------------- 1 | package zksigma 2 | 3 | import ( 4 | "fmt" 5 | "math/big" 6 | ) 7 | 8 | type InequalityProof ABCProof 9 | 10 | // InequalityProve generates a proof to show that two commitments, A and B, are not equal 11 | // Given two commitments A and B that we know the values for - a and b respectively - we 12 | // can prove that a != b without needed any new commitments, just generate a proof 13 | // There is no Inequality verify since this generates an ABCProof, so just use ABCVerify 14 | func NewInequalityProof(zkpcp ZKPCurveParams, A, B, CMTokA, CMTokB ECPoint, a, b, sk *big.Int) (*InequalityProof, error) { 15 | 16 | if a.Cmp(b) == 0 { 17 | return nil, &errorProof{"InequalityProve", "a and b should not be equal..."} 18 | } 19 | 20 | // should I check if a > b? I think that shouldn't be a problem 21 | // generate a-b for ABCProof, D will be created commitment 22 | value := new(big.Int).Sub(a, b) 23 | CM := zkpcp.Sub(A, B) 24 | 25 | CMTok := zkpcp.Sub(CMTokA, CMTokB) 26 | 27 | proof, proofStatus := NewABCProof(zkpcp, CM, CMTok, value, sk, Right) 28 | 29 | if proofStatus != nil { 30 | return nil, proofStatus 31 | } 32 | 33 | return ((*InequalityProof)(proof)), proofStatus 34 | } 35 | 36 | // Verify checks if InequalityProof ieProof with appropriate commits CM and CMTok is correct 37 | func (ieProof *InequalityProof) Verify(zkpcp ZKPCurveParams, CM, CMTok ECPoint) (bool, error) { 38 | if ieProof == nil { 39 | return false, &errorProof{"InequalityProof.Verify", fmt.Sprintf("passed proof is nil")} 40 | } 41 | 42 | return ((*ABCProof)(ieProof)).Verify(zkpcp, CM, CMTok) 43 | } 44 | -------------------------------------------------------------------------------- /zksigma.go: -------------------------------------------------------------------------------- 1 | /* 2 | **WARNING: zkSigma is research code and should not be used with sensitive data. It definitely has bugs!** 3 | 4 | zkSigma is a library for generating non-interactive zero-knowledge proofs, also known as NIZKs. The proofs in zkSigma are based on Generalized Schnorr Proofs; they can be publicly verified and do not require any trusted setup. 5 | 6 | Features: 7 | 8 | * Generating non-interactive zero-knowledge proofs for various logical statements 9 | 10 | * Simplified elliptic curve operations 11 | 12 | * Plug and Play API 13 | 14 | More info on Github 15 | */ 16 | package zksigma 17 | 18 | import ( 19 | "crypto/sha256" 20 | "math/big" 21 | 22 | "github.com/mit-dci/zksigma/btcec" 23 | ) 24 | 25 | // Side is an enum to pick what side of the proof you want to generate 26 | type Side int 27 | 28 | const ( 29 | // Left generates the left side of a proof 30 | Left Side = 0 31 | // Right generates the right side of a proof 32 | Right Side = 1 33 | ) 34 | 35 | // TestCurve is a global cache for the curve and two generator points used in the test cases. 36 | // It is equal to ZKLedger's curve - but for abstraction the actual curve parameters are 37 | // passed into the proof functions. We just test with the same params that ZKLedger uses. 38 | var TestCurve ZKPCurveParams 39 | 40 | func generateH2tothe() []ECPoint { 41 | Hslice := make([]ECPoint, 64) 42 | for i := range Hslice { 43 | m := big.NewInt(1 << uint(i)) 44 | Hslice[i].X, Hslice[i].Y = TestCurve.C.ScalarBaseMult(m.Bytes()) 45 | } 46 | return Hslice 47 | } 48 | 49 | func init() { 50 | s256 := sha256.New() 51 | hashedString := s256.Sum([]byte("This is the new random point in zksigma")) 52 | HX, HY := btcec.S256().ScalarMult(btcec.S256().Gx, btcec.S256().Gy, hashedString) 53 | TestCurve = ZKPCurveParams{ 54 | C: btcec.S256(), 55 | G: ECPoint{btcec.S256().Gx, btcec.S256().Gy}, 56 | H: ECPoint{HX, HY}, 57 | } 58 | TestCurve.HPoints = generateH2tothe() 59 | } 60 | -------------------------------------------------------------------------------- /rangeproof_test.go: -------------------------------------------------------------------------------- 1 | package zksigma 2 | 3 | import ( 4 | "crypto/rand" 5 | "math/big" 6 | "testing" 7 | ) 8 | 9 | // Copy-pasted from original apl implementation by Willy (github.com/wrv) 10 | func TestRangeProver_Verify(t *testing.T) { 11 | value, _ := rand.Int(rand.Reader, big.NewInt(1099511627775)) 12 | proof, rp, err := NewRangeProof(TestCurve, value) 13 | if err != nil { 14 | t.Fatalf("TestRangeProver_Verify failed to generate proof\n") 15 | } 16 | comm := PedCommitR(TestCurve, value, rp) 17 | if !comm.Equal(proof.ProofAggregate) { 18 | t.Error("Error computing the randomnesses used -- commitments did not check out when supposed to") 19 | } else { 20 | ok, err := proof.Verify(TestCurve, comm) 21 | if !ok { 22 | t.Errorf("** Range proof failed: %s", err) 23 | } else { 24 | 25 | } 26 | } 27 | } 28 | 29 | func TestRangeProverSerialization(t *testing.T) { 30 | value, _ := rand.Int(rand.Reader, big.NewInt(1099511627775)) 31 | proof, rp, err := NewRangeProof(TestCurve, value) 32 | if err != nil { 33 | t.Fatalf("TestRangeProverSerialization failed to generate proof\n") 34 | } 35 | proof, err = NewRangeProofFromBytes(proof.Bytes()) 36 | if err != nil { 37 | t.Fatalf("TestRangeProverSerialization failed to deserialize\n") 38 | } 39 | comm := PedCommitR(TestCurve, value, rp) 40 | if !comm.Equal(proof.ProofAggregate) { 41 | t.Error("Error computing the randomnesses used -- commitments did not check out when supposed to") 42 | } else { 43 | ok, err := proof.Verify(TestCurve, comm) 44 | if !ok { 45 | t.Errorf("** Range proof failed: %s", err) 46 | } else { 47 | 48 | } 49 | } 50 | } 51 | 52 | func TestOutOfRangeRangeProver_Verify(t *testing.T) { 53 | min := new(big.Int).Exp(new(big.Int).SetInt64(2), new(big.Int).SetInt64(64), nil) 54 | 55 | value, err := rand.Int(rand.Reader, new(big.Int).Add(new(big.Int).Sub(TestCurve.C.Params().N, min), min)) // want to make sure it's out of range 56 | if err != nil { 57 | t.Error(err) 58 | } 59 | 60 | _, _, err = NewRangeProof(TestCurve, value) 61 | if err == nil { 62 | t.Error("Computing the range proof shouldn't work but it did") 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /gspfs_test.go: -------------------------------------------------------------------------------- 1 | package zksigma 2 | 3 | import ( 4 | "crypto/rand" 5 | "testing" 6 | ) 7 | 8 | func TestGSPFS(t *testing.T) { 9 | 10 | x, err := rand.Int(rand.Reader, TestCurve.C.Params().N) 11 | if err != nil { 12 | t.Fatalf("%v\n", err) 13 | } 14 | 15 | // MUST use G here because of GSPFSProve implementation 16 | result := TestCurve.Mult(TestCurve.G, x) 17 | 18 | testProof, err := NewGSPFSProof(TestCurve, result, x) 19 | if err != nil { 20 | t.Fatalf("%v\n", err) 21 | } 22 | 23 | status, err := testProof.Verify(TestCurve, result) 24 | if !status && err == nil { 25 | t.Logf("x : %v\n", x) 26 | t.Logf("randPoint : %v\n", result) 27 | t.Logf("testProof : %v\n", testProof) 28 | t.Fatalf("GSPFS Proof didn't generate properly - 1\n") 29 | } 30 | 31 | // Using H here should break the proof 32 | result = TestCurve.Mult(TestCurve.H, x) 33 | 34 | t.Logf("Next GSPFSVerify should fail\n") 35 | status, err = testProof.Verify(TestCurve, result) 36 | if status && err != nil { 37 | t.Logf("x : %v\n", x) 38 | t.Logf("randPoint : %v\n", result) 39 | t.Logf("testProof : %v\n", testProof) 40 | t.Fatalf("GSPFS Proof should not have worked - 2\n") 41 | } 42 | 43 | } 44 | 45 | func TestGSPFSSerialization(t *testing.T) { 46 | value, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 47 | Base := TestCurve.G 48 | CM := TestCurve.Mult(TestCurve.G, value) 49 | proof, err := NewGSPFSProofBase(TestCurve, Base, CM, value) 50 | proof, err = NewGSPFSProofFromBytes(proof.Bytes()) 51 | if err != nil { 52 | t.Fatalf("TestGSPFSSerialization failed to deserialize\n") 53 | } 54 | ok, err := proof.Verify(TestCurve, CM) 55 | if !ok || err != nil { 56 | t.Fatalf("TestGSPFSSerialization failed to verify\n") 57 | } 58 | 59 | } 60 | 61 | func BenchmarkGSPFS_AnyBase(b *testing.B) { 62 | value, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 63 | Base := TestCurve.G 64 | CM := TestCurve.Mult(TestCurve.G, value) 65 | b.ResetTimer() 66 | for ii := 0; ii < b.N; ii++ { 67 | NewGSPFSProofBase(TestCurve, Base, CM, value) 68 | } 69 | } 70 | 71 | func BenchmarkGSPFS_Verify(b *testing.B) { 72 | value, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 73 | Base := TestCurve.G 74 | CM := TestCurve.Mult(TestCurve.G, value) 75 | proof, err := NewGSPFSProofBase(TestCurve, Base, CM, value) 76 | if err != nil { 77 | b.Fatalf("%v\n", err) 78 | } 79 | 80 | for ii := 0; ii < b.N; ii++ { 81 | proof.Verify(TestCurve, CM) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /btcec/privkey.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013-2016 The btcsuite developers 2 | // Use of this source code is governed by an ISC 3 | // license that can be found in the LICENSE file. 4 | 5 | package btcec 6 | 7 | import ( 8 | "crypto/ecdsa" 9 | "crypto/elliptic" 10 | "crypto/rand" 11 | "math/big" 12 | ) 13 | 14 | // PrivateKey wraps an ecdsa.PrivateKey as a convenience mainly for signing 15 | // things with the the private key without having to directly import the ecdsa 16 | // package. 17 | type PrivateKey ecdsa.PrivateKey 18 | 19 | // PrivKeyFromBytes returns a private and public key for `curve' based on the 20 | // private key passed as an argument as a byte slice. 21 | func PrivKeyFromBytes(curve elliptic.Curve, pk []byte) (*PrivateKey, 22 | *PublicKey) { 23 | x, y := curve.ScalarBaseMult(pk) 24 | 25 | priv := &ecdsa.PrivateKey{ 26 | PublicKey: ecdsa.PublicKey{ 27 | Curve: curve, 28 | X: x, 29 | Y: y, 30 | }, 31 | D: new(big.Int).SetBytes(pk), 32 | } 33 | 34 | return (*PrivateKey)(priv), (*PublicKey)(&priv.PublicKey) 35 | } 36 | 37 | // NewPrivateKey is a wrapper for ecdsa.GenerateKey that returns a PrivateKey 38 | // instead of the normal ecdsa.PrivateKey. 39 | func NewPrivateKey(curve elliptic.Curve) (*PrivateKey, error) { 40 | key, err := ecdsa.GenerateKey(curve, rand.Reader) 41 | if err != nil { 42 | return nil, err 43 | } 44 | return (*PrivateKey)(key), nil 45 | } 46 | 47 | // PubKey returns the PublicKey corresponding to this private key. 48 | func (p *PrivateKey) PubKey() *PublicKey { 49 | return (*PublicKey)(&p.PublicKey) 50 | } 51 | 52 | // ToECDSA returns the private key as a *ecdsa.PrivateKey. 53 | func (p *PrivateKey) ToECDSA() *ecdsa.PrivateKey { 54 | return (*ecdsa.PrivateKey)(p) 55 | } 56 | 57 | // Sign generates an ECDSA signature for the provided hash (which should be the result 58 | // of hashing a larger message) using the private key. Produced signature 59 | // is deterministic (same message and same key yield the same signature) and canonical 60 | // in accordance with RFC6979 and BIP0062. 61 | func (p *PrivateKey) Sign(hash []byte) (*Signature, error) { 62 | return signRFC6979(p, hash) 63 | } 64 | 65 | // PrivKeyBytesLen defines the length in bytes of a serialized private key. 66 | const PrivKeyBytesLen = 32 67 | 68 | // Serialize returns the private key number d as a big-endian binary-encoded 69 | // number, padded to a length of 32 bytes. 70 | func (p *PrivateKey) Serialize() []byte { 71 | b := make([]byte, 0, PrivKeyBytesLen) 72 | return paddedAppend(PrivKeyBytesLen, b, p.ToECDSA().D.Bytes()) 73 | } 74 | -------------------------------------------------------------------------------- /btcec/genprecomps.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The btcsuite developers 2 | // Use of this source code is governed by an ISC 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file is ignored during the regular build due to the following build tag. 6 | // It is called by go generate and used to automatically generate pre-computed 7 | // tables used to accelerate operations. 8 | // +build ignore 9 | 10 | package main 11 | 12 | import ( 13 | "bytes" 14 | "compress/zlib" 15 | "encoding/base64" 16 | "fmt" 17 | "log" 18 | "os" 19 | 20 | "github.com/mit-dci/zksigma/btcec" 21 | ) 22 | 23 | func main() { 24 | fi, err := os.Create("secp256k1.go") 25 | if err != nil { 26 | log.Fatal(err) 27 | } 28 | defer fi.Close() 29 | 30 | fi2, err2 := os.Create("secp256k1H.go") 31 | if err2 != nil { 32 | log.Fatal(err2) 33 | } 34 | defer fi2.Close() 35 | 36 | // Compress the serialized byte points. 37 | serialized := btcec.S256().SerializedBytePoints() 38 | var compressed bytes.Buffer 39 | w := zlib.NewWriter(&compressed) 40 | if _, err := w.Write(serialized); err != nil { 41 | fmt.Println(err) 42 | os.Exit(1) 43 | } 44 | w.Close() 45 | 46 | serializedH := btcec.S256().SerializedBytePointsH() 47 | var compressedH bytes.Buffer 48 | wH := zlib.NewWriter(&compressedH) 49 | if _, err := wH.Write(serializedH); err != nil { 50 | fmt.Println(err) 51 | os.Exit(1) 52 | } 53 | wH.Close() 54 | 55 | // Encode the compressed byte points with base64. 56 | encoded := make([]byte, base64.StdEncoding.EncodedLen(compressed.Len())) 57 | base64.StdEncoding.Encode(encoded, compressed.Bytes()) 58 | 59 | encodedH := make([]byte, base64.StdEncoding.EncodedLen(compressedH.Len())) 60 | base64.StdEncoding.Encode(encodedH, compressedH.Bytes()) 61 | 62 | fmt.Fprintln(fi, "// Copyright (c) 2015 The btcsuite developers") 63 | fmt.Fprintln(fi, "// Use of this source code is governed by an ISC") 64 | fmt.Fprintln(fi, "// license that can be found in the LICENSE file.") 65 | fmt.Fprintln(fi) 66 | fmt.Fprintln(fi, "package btcec") 67 | fmt.Fprintln(fi) 68 | fmt.Fprintln(fi, "// Auto-generated file (see genprecomps.go)") 69 | fmt.Fprintln(fi, "// DO NOT EDIT") 70 | fmt.Fprintln(fi) 71 | fmt.Fprintf(fi, "var secp256k1BytePoints = %q\n", string(encoded)) 72 | 73 | a1, b1, a2, b2 := btcec.S256().EndomorphismVectors() 74 | fmt.Println("The following values are the computed linearly " + 75 | "independent vectors needed to make use of the secp256k1 " + 76 | "endomorphism:") 77 | fmt.Printf("a1: %x\n", a1) 78 | fmt.Printf("b1: %x\n", b1) 79 | fmt.Printf("a2: %x\n", a2) 80 | fmt.Printf("b2: %x\n", b2) 81 | 82 | // H 83 | fmt.Fprintln(fi2, "// Copyright (c) 2015 The btcsuite developers") 84 | fmt.Fprintln(fi2, "// Use of this source code is governed by an ISC") 85 | fmt.Fprintln(fi2, "// license that can be found in the LICENSE file.") 86 | fmt.Fprintln(fi2) 87 | fmt.Fprintln(fi2, "package btcec") 88 | fmt.Fprintln(fi2) 89 | fmt.Fprintln(fi2, "// Auto-generated file (see genprecomps.go)") 90 | fmt.Fprintln(fi2, "// DO NOT EDIT") 91 | fmt.Fprintln(fi2) 92 | fmt.Fprintf(fi2, "var secp256k1BytePointsH = %q\n", string(encodedH)) 93 | } 94 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # zkSigma 2 | 3 | **WARNING: zkSigma is research code and should not be used with sensitive data. It definitely has bugs!** 4 | 5 | zkSigma is a library for generating non-interactive zero-knowledge proofs, also 6 | known as NIZKs. The proofs in zkSigma are based on Generalized Schnorr Proofs; 7 | they can be publicly verified and do not require any trusted setup. 8 | 9 | Features: 10 | - Generating non-interactive zero-knowledge proofs for various logical statements 11 | - Simplified elliptic curve operations 12 | - Plug and Play API 13 | - Built in serialization and deserialization of proofs 14 | 15 | Statements that can be proved: 16 | - I can open a Pedersen Commitment `A`(=`aG+uH`) (Open) 17 | - I know the discrete log of a commitment `A`(=`aG`) (GSPFS Proof) 18 | - I know the discrete log of commitments `A`(=`xG`) and `B`(=`xH`) and they are equal (Equivalence Proof) 19 | - I know the discrete log of either commitment `A` or `B` (Disjunctive Proof) 20 | - I know that the blinding factor of commitments `A` and `B` is equal (Consistency Proof) 21 | - I know `a`, `b`, and `c` in commitments `A`, `B` and `C` and `a * b = c` (ABC Proof) 22 | - I know `a` and `b` in commitments `A` and `B` and `a != b` (InequalityProof is a special case of ABC Proof) 23 | 24 | 25 | Running the tests: 26 | - Will show debugging messages, good for debugging a proof that is not generating or verifying 27 | ``` 28 | go test -debug1 29 | ``` 30 | - Run rangeproof tests (default: off) 31 | ``` 32 | go test -range 33 | ``` 34 | 35 | Notation: 36 | - lower case letters are scalars (`a`, `b`, `c`, `x`,...) 37 | - lower case letters starting with `u` are randomly generated scalars (`ua`, `ub`, `u1`, `u2`, ...) 38 | - upper case letters are always elliptic curve points (type `ECPoint`) (`G`, `H`, `A`, `B`,...) 39 | - `G` = Base Point of `ZKCurve.C` 40 | - `H` = Secondary Base Point whose relation to `G` should not be known 41 | - `A`, `B`, `CM`, `CMTok`, etc, are usually of the form `vG+uH` unless otherwise stated 42 | - `sk` and `PK` are always secret key and public key. `sk` is a randomly chosen scalar. `PK = sk * H` 43 | - `CM` = Commitment of the form `aG + uH` 44 | - `CMTok` = Commitment Token of the form `ua * PK` 45 | 46 | ## Articles related to NIZK Proofs 47 | 48 | [Sigma Protocols](http://www.cs.au.dk/~ivan/Sigma.pdf) 49 | : A three step protocol where a prover and verifier can exchange a commitment and a challenge in order to verify proof of knowledge behind the commitment. [Simple explanation here.](https://en.wikipedia.org/wiki/Proof_of_knowledge#Sigma_protocols) 50 | 51 | 52 | [Unifying Zero-Knowledge Proofs of Knowledge](ftp://ftp.inf.ethz.ch/pub/crypto/publications/Maurer09.pdf) 53 | : This paper explains zero-knowledge proof of knowledge and provides the foundation on which all our proofs are built upon. 54 | 55 | [zkLedger](https://www.usenix.org/conference/nsdi18/presentation/narula) 56 | : A privacy preserving distributed ledger that allows for verifiable auditing. The original motivation for creating zksigma. 57 | 58 | [Bulletproofs](https://doc-internal.dalek.rs/bulletproofs/inner_product_proof/index.html) 59 | : A faster form of rangeproofs that only requires log(n) steps to verify that a commitment is within a given range. This might be integrated into this library in the future. 60 | 61 | ## Comparison to zkSNARKS 62 | 63 | You cannot use zkSigma to prove general statements. 64 | -------------------------------------------------------------------------------- /consistency_test.go: -------------------------------------------------------------------------------- 1 | package zksigma 2 | 3 | import ( 4 | "crypto/rand" 5 | "testing" 6 | ) 7 | 8 | func TestConsistency(t *testing.T) { 9 | x, err := rand.Int(rand.Reader, TestCurve.C.Params().N) 10 | if err != nil { 11 | t.Fatalf("%v\n", err) 12 | } 13 | 14 | sk, err := rand.Int(rand.Reader, TestCurve.C.Params().N) 15 | if err != nil { 16 | t.Fatalf("%v\n", err) 17 | } 18 | 19 | pk := TestCurve.Mult(TestCurve.H, sk) 20 | 21 | comm, u, err := PedCommit(TestCurve, x) 22 | if err != nil { 23 | t.Fatalf("%v\n", err) 24 | } 25 | 26 | y := TestCurve.Mult(pk, u) 27 | 28 | conProof, status1 := NewConsistencyProof(TestCurve, comm, y, pk, x, u) 29 | 30 | if status1 != nil { 31 | t.Fatalf("TestConsistency - incorrect error message for correct proof, case 1\n") 32 | } 33 | 34 | t.Logf(" [testing] Testing correct consistency proof\n") 35 | check, err := conProof.Verify(TestCurve, comm, y, pk) 36 | if !check || err != nil { 37 | t.Fatalf("Error -- Proof should be correct\n") 38 | } 39 | 40 | t.Logf(" [testing] Next proof should fail\n") 41 | 42 | _, status2 := NewConsistencyProof(TestCurve, y, comm, pk, x, u) 43 | 44 | if status2 == nil { 45 | t.Fatalf("TestConsistency - incorrect error message for correct proof, case 2\n") 46 | } 47 | } 48 | 49 | func TestConsistencySerialization(t *testing.T) { 50 | x, err := rand.Int(rand.Reader, TestCurve.C.Params().N) 51 | if err != nil { 52 | t.Fatalf("%v\n", err) 53 | } 54 | 55 | sk, err := rand.Int(rand.Reader, TestCurve.C.Params().N) 56 | if err != nil { 57 | t.Fatalf("%v\n", err) 58 | } 59 | 60 | pk := TestCurve.Mult(TestCurve.H, sk) 61 | 62 | comm, u, err := PedCommit(TestCurve, x) 63 | if err != nil { 64 | t.Fatalf("%v\n", err) 65 | } 66 | 67 | y := TestCurve.Mult(pk, u) 68 | 69 | conProof, status1 := NewConsistencyProof(TestCurve, comm, y, pk, x, u) 70 | 71 | if status1 != nil { 72 | t.Fatalf("TestConsistency - incorrect error message for correct proof, case 1\n") 73 | } 74 | 75 | conProof, status1 = NewConsistencyProofFromBytes(conProof.Bytes()) 76 | if status1 != nil { 77 | t.Fatalf("TestConsistency - failed to deserialize \n") 78 | } 79 | t.Logf(" [testing] Testing correct consistency proof\n") 80 | check, err := conProof.Verify(TestCurve, comm, y, pk) 81 | if !check || err != nil { 82 | t.Fatalf("Error -- Proof should be correct\n") 83 | } 84 | } 85 | 86 | func BenchmarkConsistencyProve(b *testing.B) { 87 | value, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 88 | 89 | sk, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 90 | PK := TestCurve.Mult(TestCurve.H, sk) 91 | 92 | CM, randVal, err := PedCommit(TestCurve, value) 93 | if err != nil { 94 | b.Fatalf("%v\n", err) 95 | } 96 | 97 | CMTok := TestCurve.Mult(PK, randVal) 98 | 99 | b.ResetTimer() 100 | for ii := 0; ii < b.N; ii++ { 101 | NewConsistencyProof(TestCurve, CM, CMTok, PK, value, randVal) 102 | } 103 | } 104 | 105 | func BenchmarkConsistencyVerify(b *testing.B) { 106 | value, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 107 | 108 | sk, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 109 | PK := TestCurve.Mult(TestCurve.H, sk) 110 | 111 | CM, randVal, err := PedCommit(TestCurve, value) 112 | if err != nil { 113 | b.Fatalf("%v\n", err) 114 | } 115 | 116 | CMTok := TestCurve.Mult(PK, randVal) 117 | proof, _ := NewConsistencyProof(TestCurve, CM, CMTok, PK, value, randVal) 118 | b.ResetTimer() 119 | for ii := 0; ii < b.N; ii++ { 120 | proof.Verify(TestCurve, CM, CMTok, PK) 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /btcec/precompute.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The btcsuite developers 2 | // Use of this source code is governed by an ISC 3 | // license that can be found in the LICENSE file. 4 | 5 | package btcec 6 | 7 | import ( 8 | "compress/zlib" 9 | "encoding/base64" 10 | "encoding/binary" 11 | "io/ioutil" 12 | "strings" 13 | ) 14 | 15 | //go:generate go run -tags gensecp256k1 genprecomps.go 16 | 17 | // loadS256BytePoints decompresses and deserializes the pre-computed byte points 18 | // used to accelerate scalar base multiplication for the secp256k1 curve. This 19 | // approach is used since it allows the compile to use significantly less ram 20 | // and be performed much faster than it is with hard-coding the final in-memory 21 | // data structure. At the same time, it is quite fast to generate the in-memory 22 | // data structure at init time with this approach versus computing the table. 23 | func loadS256BytePoints() error { 24 | // There will be no byte points to load when generating them. 25 | bp := secp256k1BytePoints 26 | if len(bp) == 0 { 27 | return nil 28 | } 29 | 30 | // Decompress the pre-computed table used to accelerate scalar base 31 | // multiplication. 32 | decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(bp)) 33 | r, err := zlib.NewReader(decoder) 34 | if err != nil { 35 | return err 36 | } 37 | serialized, err := ioutil.ReadAll(r) 38 | if err != nil { 39 | return err 40 | } 41 | 42 | // Deserialize the precomputed byte points and set the curve to them. 43 | offset := 0 44 | var bytePoints [32][256][3]fieldVal 45 | for byteNum := 0; byteNum < 32; byteNum++ { 46 | // All points in this window. 47 | for i := 0; i < 256; i++ { 48 | px := &bytePoints[byteNum][i][0] 49 | py := &bytePoints[byteNum][i][1] 50 | pz := &bytePoints[byteNum][i][2] 51 | for i := 0; i < 10; i++ { 52 | px.n[i] = binary.LittleEndian.Uint32(serialized[offset:]) 53 | offset += 4 54 | } 55 | for i := 0; i < 10; i++ { 56 | py.n[i] = binary.LittleEndian.Uint32(serialized[offset:]) 57 | offset += 4 58 | } 59 | for i := 0; i < 10; i++ { 60 | pz.n[i] = binary.LittleEndian.Uint32(serialized[offset:]) 61 | offset += 4 62 | } 63 | } 64 | } 65 | secp256k1.bytePoints = &bytePoints 66 | return nil 67 | } 68 | 69 | func loadS256BytePointsH() error { 70 | // There will be no byte points to load when generating them. 71 | bp := secp256k1BytePointsH 72 | if len(bp) == 0 { 73 | return nil 74 | } 75 | 76 | // Decompress the pre-computed table used to accelerate scalar base 77 | // multiplication. 78 | decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(bp)) 79 | r, err := zlib.NewReader(decoder) 80 | if err != nil { 81 | return err 82 | } 83 | serialized, err := ioutil.ReadAll(r) 84 | if err != nil { 85 | return err 86 | } 87 | 88 | // Deserialize the precomputed byte points and set the curve to them. 89 | offset := 0 90 | var bytePoints [32][256][3]fieldVal 91 | for byteNum := 0; byteNum < 32; byteNum++ { 92 | // All points in this window. 93 | for i := 0; i < 256; i++ { 94 | px := &bytePoints[byteNum][i][0] 95 | py := &bytePoints[byteNum][i][1] 96 | pz := &bytePoints[byteNum][i][2] 97 | for i := 0; i < 10; i++ { 98 | px.n[i] = binary.LittleEndian.Uint32(serialized[offset:]) 99 | offset += 4 100 | } 101 | for i := 0; i < 10; i++ { 102 | py.n[i] = binary.LittleEndian.Uint32(serialized[offset:]) 103 | offset += 4 104 | } 105 | for i := 0; i < 10; i++ { 106 | pz.n[i] = binary.LittleEndian.Uint32(serialized[offset:]) 107 | offset += 4 108 | } 109 | } 110 | } 111 | secp256k1.bytePointsH = &bytePoints 112 | return nil 113 | } 114 | -------------------------------------------------------------------------------- /inequality_test.go: -------------------------------------------------------------------------------- 1 | package zksigma 2 | 3 | import ( 4 | "crypto/rand" 5 | "math/big" 6 | "testing" 7 | ) 8 | 9 | func TestInequalityProve(t *testing.T) { 10 | 11 | sk, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 12 | a, _ := rand.Int(rand.Reader, big.NewInt(10000000000)) // "realistic range" 13 | b, _ := rand.Int(rand.Reader, big.NewInt(10000000000)) // "realistic range" 14 | A, ua, err := PedCommit(TestCurve, a) 15 | 16 | if err != nil { 17 | t.Fatalf("%v\n", err) 18 | } 19 | 20 | B, ub, err := PedCommit(TestCurve, b) 21 | if err != nil { 22 | t.Fatalf("%v\n", err) 23 | } 24 | 25 | PK := TestCurve.Mult(TestCurve.H, sk) 26 | 27 | // Even though we generated the values for ua and ub in this test case, we do not 28 | // need to know ua or ub, only the commitment tokens are needed 29 | CMTokA := TestCurve.Mult(PK, ua) 30 | CMTokB := TestCurve.Mult(PK, ub) 31 | 32 | aProof, status := NewInequalityProof(TestCurve, A, B, CMTokA, CMTokB, a, b, sk) 33 | 34 | if status != nil { 35 | proofStatus(status.(*errorProof)) 36 | t.Logf("ABCProof for InequalityProve failed to generate!\n") 37 | t.Fatalf("ABCProof for InequalityProve failed\n") 38 | } 39 | 40 | check, err := aProof.Verify(TestCurve, TestCurve.Sub(A, B), TestCurve.Sub(CMTokA, CMTokB)) 41 | if !check || err != nil { 42 | t.Logf("ABCProof for InequalityProve failed to verify!\n") 43 | t.Fatalf("ABCVerify for InequalityProve failed\n") 44 | } 45 | 46 | // Swapped positions of commitments, tokens and values, should work just fine 47 | aProof, status = NewInequalityProof(TestCurve, B, A, CMTokB, CMTokA, b, a, sk) 48 | 49 | if status != nil { 50 | proofStatus(status.(*errorProof)) 51 | t.Logf("ABCProof for InequalityProve failed to generate!\n") 52 | t.Fatalf("ABCProof for InequalityProve failed\n") 53 | } 54 | 55 | check, err = aProof.Verify(TestCurve, TestCurve.Sub(B, A), TestCurve.Sub(CMTokB, CMTokA)) 56 | if !check || err != nil { 57 | t.Logf("ABCProof for InequalityProve failed to verify!\n") 58 | t.Fatalf("ABCVerify for InequalityProve failed\n") 59 | } 60 | 61 | // Mismatched commitments and values, a proof does generate but the 62 | // verification step will catch the false proof. 63 | // Use the -debug1 flag to see this in action 64 | aProof, status = NewInequalityProof(TestCurve, A, B, CMTokA, CMTokB, b, a, sk) 65 | 66 | if status != nil { 67 | proofStatus(status.(*errorProof)) 68 | t.Logf("ABCProof for InequalityProve failed to generate!\n") 69 | t.Fatalf("ABCProof for InequalityProve failed\n") 70 | } 71 | 72 | check, err = aProof.Verify(TestCurve, TestCurve.Sub(A, B), TestCurve.Sub(CMTokA, CMTokB)) 73 | if check || err == nil { 74 | t.Logf("ABCProof for InequalityProve failed to verify!\n") 75 | t.Fatalf("ABCVerify for InequalityProve failed\n") 76 | } 77 | 78 | } 79 | 80 | func BenchmarkInequalityProve(b *testing.B) { 81 | 82 | sk, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 83 | a, _ := rand.Int(rand.Reader, big.NewInt(10000000000)) // "realistic range" 84 | bValue, _ := rand.Int(rand.Reader, big.NewInt(10000000000)) // "realistic range" 85 | A, ua, err := PedCommit(TestCurve, a) 86 | 87 | if err != nil { 88 | b.Fatalf("%v\n", err) 89 | } 90 | 91 | B, ub, err := PedCommit(TestCurve, bValue) 92 | if err != nil { 93 | b.Fatalf("%v\n", err) 94 | } 95 | 96 | PK := TestCurve.Mult(TestCurve.H, sk) 97 | 98 | // even though we generated the values for ua and ub in this test case, we do not 99 | // need to know ua or ub, only the commitment tokens, which is already used in many other proofs 100 | CMTokA := TestCurve.Mult(PK, ua) 101 | CMTokB := TestCurve.Mult(PK, ub) 102 | 103 | b.ResetTimer() 104 | for ii := 0; ii < b.N; ii++ { 105 | NewInequalityProof(TestCurve, A, B, CMTokA, CMTokB, a, bValue, sk) 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /equivalence_test.go: -------------------------------------------------------------------------------- 1 | package zksigma 2 | 3 | import ( 4 | "crypto/rand" 5 | "math/big" 6 | "testing" 7 | ) 8 | 9 | func TestEquivalence(t *testing.T) { 10 | 11 | x, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 12 | Base1 := TestCurve.G 13 | Result1 := TestCurve.Mult(Base1, x) 14 | 15 | Base2 := TestCurve.H 16 | Result2 := TestCurve.Mult(Base2, x) 17 | 18 | eqProof, status1 := NewEquivalenceProof(TestCurve, Base1, Result1, Base2, Result2, x) 19 | 20 | if status1 != nil { 21 | proofStatus(status1.(*errorProof)) 22 | t.Fatalf("error code should have indicated successful proof") 23 | } 24 | 25 | check, err := eqProof.Verify(TestCurve, Base1, Result1, Base2, Result2) 26 | if !check || err != nil { 27 | t.Logf("Base1 : %v\n", Base1) 28 | t.Logf("Result1 : %v\n", Result1) 29 | t.Logf("Base2 : %v\n", Base2) 30 | t.Logf("Result2 : %v\n", Result2) 31 | t.Logf("Proof : %v \n", eqProof) 32 | t.Fatalf("Equivalence Proof verification failed") 33 | } 34 | 35 | t.Logf("Next comparison should fail\n") 36 | 37 | // Bases swapped shouldn't work 38 | check, err = eqProof.Verify(TestCurve, Base2, Result1, Base1, Result2) 39 | 40 | if check || err == nil { 41 | t.Logf("Base1 : %v\n", Base1) 42 | t.Logf("Result1 : %v\n", Result1) 43 | t.Logf("Base2 : %v\n", Base2) 44 | t.Logf("Result2 : %v\n", Result2) 45 | t.Logf("Proof : %v \n", eqProof) 46 | t.Fatalf("Equivalence Proof verification doesn't work") 47 | } 48 | 49 | t.Logf("Next comparison should fail\n") 50 | // Bad proof 51 | eqProof.HiddenValue = big.NewInt(-1) 52 | check, err = eqProof.Verify(TestCurve, Base2, Result1, Base1, Result2) 53 | if check || err == nil { 54 | t.Logf("Base1 : %v\n", Base1) 55 | t.Logf("Result1 : %v\n", Result1) 56 | t.Logf("Base2 : %v\n", Base2) 57 | t.Logf("Result2 : %v\n", Result2) 58 | t.Logf("Proof : %v \n", eqProof) 59 | t.Fatalf("Equivalence Proof verification doesn't work") 60 | } 61 | 62 | x, _ = rand.Int(rand.Reader, TestCurve.C.Params().N) 63 | _, status2 := NewEquivalenceProof(TestCurve, Base1, Result1, Base2, Result2, x) 64 | 65 | // here I check proofStatus in the else statement because I want to make sure 66 | // the failed case will raise an error 67 | if status2 == nil { 68 | t.Fatalf("error code should have indicated failed proof") 69 | } else { 70 | proofStatus(status2.(*errorProof)) 71 | } 72 | 73 | } 74 | 75 | func TestEquivSerialization(t *testing.T) { 76 | value, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 77 | Base1 := TestCurve.G 78 | Result1 := TestCurve.Mult(Base1, value) 79 | 80 | Base2 := TestCurve.H 81 | Result2 := TestCurve.Mult(Base2, value) 82 | 83 | proof, _ := NewEquivalenceProof(TestCurve, Base1, Result1, Base2, Result2, value) 84 | proof, err := NewEquivalenceProofFromBytes(proof.Bytes()) 85 | if err != nil { 86 | t.Fatalf("TestEquivSerialization failed to deserialize\n") 87 | } 88 | ok, err := proof.Verify(TestCurve, Base1, Result1, Base2, Result2) 89 | if !ok || err != nil { 90 | t.Fatalf("TestEquivSerialization failed to verify\n") 91 | } 92 | 93 | } 94 | 95 | func BenchmarkEquivProve(b *testing.B) { 96 | value, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 97 | Base1 := TestCurve.G 98 | Result1 := TestCurve.Mult(Base1, value) 99 | 100 | Base2 := TestCurve.H 101 | Result2 := TestCurve.Mult(Base2, value) 102 | b.ResetTimer() 103 | for ii := 0; ii < b.N; ii++ { 104 | NewEquivalenceProof(TestCurve, Base1, Result1, Base2, Result2, value) 105 | } 106 | } 107 | 108 | func BenchmarkEquivVerify(b *testing.B) { 109 | value, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 110 | Base1 := TestCurve.G 111 | Result1 := TestCurve.Mult(Base1, value) 112 | 113 | Base2 := TestCurve.H 114 | Result2 := TestCurve.Mult(Base2, value) 115 | proof, _ := NewEquivalenceProof(TestCurve, Base1, Result1, Base2, Result2, value) 116 | b.ResetTimer() 117 | for ii := 0; ii < b.N; ii++ { 118 | proof.Verify(TestCurve, Base1, Result1, Base2, Result2) 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /gspfs.go: -------------------------------------------------------------------------------- 1 | package zksigma 2 | 3 | import ( 4 | "bytes" 5 | "crypto/rand" 6 | "fmt" 7 | "math/big" 8 | ) 9 | 10 | // GSPFSProof is proof of knowledge of x in commitment A(=xG) 11 | // GSPFS is Generalized Schnorr Proofs with Fiat-Shamir transform. 12 | // 13 | // Public: generator points G and H 14 | // 15 | // Prover Verifier 16 | // ====== ======== 17 | // know x 18 | // A = xG learns A 19 | // selects random u 20 | // T1 = uG 21 | // c = HASH(G, xG, uG) 22 | // s = u + c * x 23 | // 24 | // T1, s, c --------------------------> 25 | // c ?= HASH(G, A, T1) 26 | // sG ?= T1 + cA 27 | type GSPFSProof struct { 28 | Base ECPoint // Base point 29 | RandCommit ECPoint // this is H = uG, where u is random value and G is a generator point 30 | HiddenValue *big.Int // s = x * c + u, here c is the challenge and x is what we want to prove knowledge of 31 | Challenge *big.Int // challenge string hash sum, only use for sanity checks 32 | } 33 | 34 | // NewGSPFSProof generates a Schnorr proof for the value x using the 35 | // first ZKCurve base point. It checks if the passed A is indeed 36 | // value x multiplied by the generator point. 37 | func NewGSPFSProof(zkpcp ZKPCurveParams, A ECPoint, x *big.Int) (*GSPFSProof, error) { 38 | return NewGSPFSProofBase(zkpcp, zkpcp.G, A, x) 39 | } 40 | 41 | // NewGSPFSProofBase is the same as NewGSPFSProof, except it allows you to specify 42 | // your own base point in parameter base, instead of using the first base point from zkpcp. 43 | func NewGSPFSProofBase(zkpcp ZKPCurveParams, base, A ECPoint, x *big.Int) (*GSPFSProof, error) { 44 | modValue := new(big.Int).Mod(x, zkpcp.C.Params().N) 45 | 46 | // A = xG, G is any base point in this proof 47 | cX, cY := zkpcp.C.ScalarMult(base.X, base.Y, modValue.Bytes()) 48 | C := ECPoint{cX, cY} 49 | if !C.Equal(A) { 50 | return nil, &errorProof{"GSPFSProve:", "the point given is not xG"} 51 | } 52 | 53 | u, err := rand.Int(rand.Reader, zkpcp.C.Params().N) 54 | if err != nil { 55 | return nil, err 56 | } 57 | 58 | // generate random point uG 59 | uG := zkpcp.Mult(base, u) 60 | 61 | // generate hashed string challenge 62 | c := GenerateChallenge(zkpcp, A.Bytes(), uG.Bytes()) 63 | 64 | // v = u - c * x 65 | v := new(big.Int).Sub(u, new(big.Int).Mul(c, modValue)) 66 | v = v.Mod(v, zkpcp.C.Params().N) 67 | 68 | return &GSPFSProof{base, uG, v, c}, nil 69 | } 70 | 71 | // Verify (GSPFSVerify) checks if GSPFSProof proof is a valid proof for commitment A 72 | func (proof *GSPFSProof) Verify(zkpcp ZKPCurveParams, A ECPoint) (bool, error) { 73 | 74 | if proof == nil { 75 | return false, &errorProof{"GSPFSProof.Verify", fmt.Sprintf("passed proof is nil")} 76 | } 77 | 78 | // A = xG and RandCommit = uG 79 | testC := GenerateChallenge(zkpcp, A.Bytes(), proof.RandCommit.Bytes()) 80 | 81 | if testC.Cmp(proof.Challenge) != 0 { 82 | return false, &errorProof{"GSPFSProof.Verify", "calculated challenge and proof's challenge do not agree!"} 83 | } 84 | 85 | // (u - c * x)G, look at HiddenValue from GSPFS.Proof() 86 | s := zkpcp.Mult(proof.Base, proof.HiddenValue) 87 | 88 | // cResult = c(xG), we use testC as that follows the proof verficaion process more closely than using Challenge 89 | c := zkpcp.Mult(A, proof.Challenge) 90 | 91 | // cxG + (u - cx)G = uG 92 | tot := zkpcp.Add(s, c) 93 | 94 | if !proof.RandCommit.Equal(tot) { 95 | return false, &errorProof{"GSPFSProof.Verify", "proof's final value and verification final value do not agree!"} 96 | } 97 | return true, nil 98 | } 99 | 100 | // Bytes returns a byte slice with a serialized representation of GSPFSProof proof 101 | func (proof *GSPFSProof) Bytes() []byte { 102 | var buf bytes.Buffer 103 | 104 | WriteECPoint(&buf, proof.Base) 105 | WriteECPoint(&buf, proof.RandCommit) 106 | WriteBigInt(&buf, proof.HiddenValue) 107 | WriteBigInt(&buf, proof.Challenge) 108 | 109 | return buf.Bytes() 110 | } 111 | 112 | // NewGSPFSProofFromBytes returns a GSPFSProof generated from the 113 | // deserialization of byte slice b 114 | func NewGSPFSProofFromBytes(b []byte) (*GSPFSProof, error) { 115 | proof := new(GSPFSProof) 116 | buf := bytes.NewBuffer(b) 117 | proof.Base, _ = ReadECPoint(buf) 118 | proof.RandCommit, _ = ReadECPoint(buf) 119 | proof.HiddenValue, _ = ReadBigInt(buf) 120 | proof.Challenge, _ = ReadBigInt(buf) 121 | return proof, nil 122 | } 123 | -------------------------------------------------------------------------------- /disjunctive_test.go: -------------------------------------------------------------------------------- 1 | package zksigma 2 | 3 | import ( 4 | "crypto/rand" 5 | "math/big" 6 | "testing" 7 | ) 8 | 9 | func TestDisjunctive(t *testing.T) { 10 | 11 | x := big.NewInt(100) 12 | y := big.NewInt(101) 13 | 14 | Base1 := TestCurve.G 15 | Result1 := TestCurve.Mult(TestCurve.G, x) 16 | Base2 := TestCurve.H 17 | Result2 := TestCurve.Mult(TestCurve.H, y) 18 | 19 | djProofLEFT, status1 := NewDisjunctiveProof(TestCurve, Base1, Result1, Base2, Result2, x, Left) 20 | 21 | if status1 != nil { 22 | proofStatus(status1.(*errorProof)) 23 | t.Fatalf("TestDisjunctive - incorrect error message for correct proof, case 1\n") 24 | } 25 | 26 | djProofRIGHT, status2 := NewDisjunctiveProof(TestCurve, Base1, Result1, Base2, Result2, y, Right) 27 | 28 | if status2 != nil { 29 | proofStatus(status2.(*errorProof)) 30 | t.Fatalf("TestDisjunctive - incorrect error message for correct proof, case 2\n") 31 | } 32 | 33 | t.Logf("Testing DisjunctiveProof:\n") 34 | t.Logf("First djProof : ") 35 | check, err := djProofLEFT.Verify(TestCurve, Base1, Result1, Base2, Result2) 36 | if !check || err != nil { 37 | t.Fatalf("djProof failed to generate properly for left side\n") 38 | } 39 | 40 | t.Logf("Passed \n [testing] Second djProof : ") 41 | check, err = djProofRIGHT.Verify(TestCurve, Base1, Result1, Base2, Result2) 42 | if !check || err != nil { 43 | t.Fatalf("djProof failed to generate properly for right side\n") 44 | } 45 | 46 | t.Logf("Passed \n [testing] Next djProof attempt should result in an error message\n") 47 | _, status3 := NewDisjunctiveProof(TestCurve, Base1, Result1, Base2, Result2, y, Left) // This should fail 48 | 49 | if status3 == nil { 50 | t.Fatalf("TestDisjunctive - incorrect error message for incorrect proof, case 3\n") 51 | } 52 | 53 | } 54 | 55 | func TestDisjuncSerialization(t *testing.T) { 56 | value, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 57 | randVal, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 58 | Base1 := TestCurve.G 59 | Result1 := TestCurve.Mult(Base1, value) 60 | Base2 := TestCurve.H 61 | Result2 := TestCurve.Mult(Base2, randVal) 62 | proof, _ := NewDisjunctiveProof(TestCurve, Base1, Result1, Base2, Result2, value, Left) 63 | proof, err := NewDisjunctiveProofFromBytes(proof.Bytes()) 64 | if err != nil { 65 | t.Fatalf("TestDisjuncSerialization failed to deserialize\n") 66 | } 67 | ok, err := proof.Verify(TestCurve, Base1, Result1, Base2, Result2) 68 | if !ok || err != nil { 69 | t.Fatalf("TestDisjuncSerialization failed to verify\n") 70 | } 71 | 72 | } 73 | 74 | func BenchmarkDisjuncProve_LEFT(b *testing.B) { 75 | value, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 76 | randVal, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 77 | Base1 := TestCurve.G 78 | Result1 := TestCurve.Mult(Base1, value) 79 | Base2 := TestCurve.H 80 | Result2 := TestCurve.Mult(Base2, randVal) 81 | b.ResetTimer() 82 | for ii := 0; ii < b.N; ii++ { 83 | NewDisjunctiveProof(TestCurve, Base1, Result1, Base2, Result2, value, Left) 84 | } 85 | } 86 | 87 | func BenchmarkDisjuncProve_RIGHT(b *testing.B) { 88 | value, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 89 | randVal, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 90 | Base1 := TestCurve.G 91 | Result1 := TestCurve.Mult(Base1, value) 92 | Base2 := TestCurve.H 93 | Result2 := TestCurve.Mult(Base2, randVal) 94 | b.ResetTimer() 95 | for ii := 0; ii < b.N; ii++ { 96 | NewDisjunctiveProof(TestCurve, Base1, Result1, Base2, Result2, randVal, Right) 97 | } 98 | } 99 | 100 | func BenchmarkDisjuncVerify_LEFT(b *testing.B) { 101 | value, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 102 | randVal, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 103 | Base1 := TestCurve.G 104 | Result1 := TestCurve.Mult(Base1, value) 105 | Base2 := TestCurve.H 106 | Result2 := TestCurve.Mult(Base2, randVal) 107 | proof, _ := NewDisjunctiveProof(TestCurve, Base1, Result1, Base2, Result2, value, Left) 108 | b.ResetTimer() 109 | for ii := 0; ii < b.N; ii++ { 110 | proof.Verify(TestCurve, Base1, Result1, Base2, Result2) 111 | } 112 | } 113 | 114 | func BenchmarkDisjuncVerify_RIGHT(b *testing.B) { 115 | value, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 116 | randVal, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 117 | Base1 := TestCurve.G 118 | Result1 := TestCurve.Mult(Base1, value) 119 | Base2 := TestCurve.H 120 | Result2 := TestCurve.Mult(Base2, randVal) 121 | proof, _ := NewDisjunctiveProof(TestCurve, Base1, Result1, Base2, Result2, randVal, Right) 122 | b.ResetTimer() 123 | for ii := 0; ii < b.N; ii++ { 124 | proof.Verify(TestCurve, Base1, Result1, Base2, Result2) 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /equivalence.go: -------------------------------------------------------------------------------- 1 | package zksigma 2 | 3 | import ( 4 | "bytes" 5 | "crypto/rand" 6 | "fmt" 7 | "math/big" 8 | ) 9 | 10 | // EquivalenceProof is an Equivalence Proof. A proof that both A and B both use the 11 | // same scalar, x. 12 | // 13 | // Public: generator points G and H 14 | // 15 | // Prover Verifier 16 | // ====== ======== 17 | // know x 18 | // A = xG ; B = xH learns A, B 19 | // selects random u 20 | // T1 = uG 21 | // T2 = uH 22 | // c = HASH(G, H, xG, xH, uG, uH) 23 | // s = u + c * x 24 | // 25 | // T1, T2, s, c ----------------------> 26 | // c ?= HASH(G, H, A, B, T1, T2) 27 | // sG ?= T1 + cA 28 | // sH ?= T2 + cB 29 | type EquivalenceProof struct { 30 | UG ECPoint // uG is the scalar mult of u (random num) with base G 31 | UH ECPoint // uH is the scalar mult of u (random num) with base H 32 | Challenge *big.Int // Challenge is hash sum of challenge commitment 33 | HiddenValue *big.Int // Hidden Value hides the discrete log x that we want to prove equivalence for 34 | } 35 | 36 | // NewEquivalenceProof generates an equivalence proof that Result1 is the scalar multiple of base Base1, 37 | // and Result2 is the scalar multiple of base Base2 and that both results are using the same x as discrete log. 38 | func NewEquivalenceProof( 39 | zkpcp ZKPCurveParams, Base1, Result1, Base2, Result2 ECPoint, x *big.Int) (*EquivalenceProof, error) { 40 | 41 | modValue := new(big.Int).Mod(x, zkpcp.C.Params().N) 42 | check1 := zkpcp.Mult(Base1, modValue) 43 | 44 | if !check1.Equal(Result1) { 45 | return nil, &errorProof{"EquivalenceProve", "Base1 and Result1 are not related by x"} 46 | } 47 | 48 | check2 := zkpcp.Mult(Base2, modValue) 49 | if !check2.Equal(Result2) { 50 | return nil, &errorProof{"EquivalenceProve", "Base2 and Result2 are not related by x"} 51 | } 52 | 53 | // random number 54 | u, err := rand.Int(rand.Reader, zkpcp.C.Params().N) // random number to hide x later 55 | if err != nil { 56 | return nil, err 57 | } 58 | 59 | // uG 60 | uBase1 := zkpcp.Mult(Base1, u) 61 | // uH 62 | uBase2 := zkpcp.Mult(Base2, u) 63 | 64 | // HASH(G, H, xG, xH, uG, uH) 65 | Challenge := GenerateChallenge(zkpcp, Base1.Bytes(), Result1.Bytes(), 66 | Base2.Bytes(), Result2.Bytes(), 67 | uBase1.Bytes(), uBase2.Bytes()) 68 | 69 | // s = u + c * x 70 | HiddenValue := new(big.Int).Add(u, new(big.Int).Mul(Challenge, modValue)) 71 | HiddenValue = HiddenValue.Mod(HiddenValue, zkpcp.C.Params().N) 72 | 73 | return &EquivalenceProof{ 74 | uBase1, // uG 75 | uBase2, // uH 76 | Challenge, 77 | HiddenValue}, nil 78 | 79 | } 80 | 81 | // Verify checks if EquivalenceProof eqProof is a valid proof that Result1 is 82 | // the scalar multiple of base Base1, and Result2 is the scalar multiple of base 83 | // Base2. Both using the same x as discrete log. 84 | func (eqProof *EquivalenceProof) Verify( 85 | zkpcp ZKPCurveParams, Base1, Result1, Base2, Result2 ECPoint) (bool, error) { 86 | 87 | if eqProof == nil { 88 | return false, &errorProof{"EquivalenceVerify", fmt.Sprintf("passed proof is nil")} 89 | } 90 | 91 | // Regenerate challenge string 92 | c := GenerateChallenge(zkpcp, Base1.Bytes(), Result1.Bytes(), 93 | Base2.Bytes(), Result2.Bytes(), 94 | eqProof.UG.Bytes(), eqProof.UH.Bytes()) 95 | 96 | if c.Cmp(eqProof.Challenge) != 0 { 97 | return false, &errorProof{"EquivalenceVerify", fmt.Sprintf("challenge comparison failed. proof: %v calculated: %v", 98 | eqProof.Challenge, c)} 99 | } 100 | 101 | // sG ?= uG + cA 102 | sG := zkpcp.Mult(Base1, eqProof.HiddenValue) 103 | cG := zkpcp.Mult(Result1, eqProof.Challenge) 104 | test := zkpcp.Add(eqProof.UG, cG) 105 | 106 | if !sG.Equal(test) { 107 | return false, &errorProof{"EquivalenceVerify", "sG comparison did not pass"} 108 | } 109 | 110 | // sH ?= uH + cB 111 | sH := zkpcp.Mult(Base2, eqProof.HiddenValue) 112 | cH := zkpcp.Mult(Result2, eqProof.Challenge) 113 | test = zkpcp.Add(eqProof.UH, cH) 114 | 115 | if !sH.Equal(test) { 116 | return false, &errorProof{"EquivalenceVerify", "sH comparison did not pass"} 117 | } 118 | 119 | // All three checks passed, proof must be correct 120 | return true, nil 121 | 122 | } 123 | 124 | // Bytes returns a byte slice with a serialized representation of EquivalenceProof proof 125 | func (proof *EquivalenceProof) Bytes() []byte { 126 | var buf bytes.Buffer 127 | 128 | WriteECPoint(&buf, proof.UG) 129 | WriteECPoint(&buf, proof.UH) 130 | WriteBigInt(&buf, proof.Challenge) 131 | WriteBigInt(&buf, proof.HiddenValue) 132 | 133 | return buf.Bytes() 134 | } 135 | 136 | // NewEquivalenceProofFromBytes returns a EquivalenceProof generated from the 137 | // deserialization of byte slice b 138 | func NewEquivalenceProofFromBytes(b []byte) (*EquivalenceProof, error) { 139 | proof := new(EquivalenceProof) 140 | buf := bytes.NewBuffer(b) 141 | proof.UG, _ = ReadECPoint(buf) 142 | proof.UH, _ = ReadECPoint(buf) 143 | proof.Challenge, _ = ReadBigInt(buf) 144 | proof.HiddenValue, _ = ReadBigInt(buf) 145 | return proof, nil 146 | } 147 | -------------------------------------------------------------------------------- /consistency.go: -------------------------------------------------------------------------------- 1 | package zksigma 2 | 3 | import ( 4 | "bytes" 5 | "crypto/rand" 6 | "fmt" 7 | "math/big" 8 | ) 9 | 10 | // ConsistencyProof is similar to EquivalenceProof except that we 11 | // make some assumptions about the public info. Here we want to prove 12 | // that the r used in CM and Y are the same. 13 | // 14 | // Public: 15 | // - generator points G and H, 16 | // - PK (pubkey) = skH // sk = secret key 17 | // - CM (commitment) = vG + rH 18 | // - CMTok = rPK 19 | // 20 | // Prover Verifier 21 | // ====== ======== 22 | // selects v and r for commitments 23 | // CM = vG + rH; CMTok = rPK learns CM, CMTok 24 | // selects random u1, u2 25 | // T1 = u1G + u2H 26 | // T2 = u2PK 27 | // c = HASH(G, H, T1, T2, PK, CM, CMTok) 28 | // s1 = u1 + c * v 29 | // s2 = u2 + c * r 30 | // 31 | // T1, T2, c, s1, s2 -----------------> 32 | // c ?= HASH(G, H, T1, T2, PK, CM, CMTok) 33 | // s1G + s2H ?= T1 + cCM 34 | // s2PK ?= T2 + cCMTok 35 | type ConsistencyProof struct { 36 | T1 ECPoint 37 | T2 ECPoint 38 | Challenge *big.Int 39 | S1 *big.Int // s1 - but capitalized to allow access from outside of zksigma 40 | S2 *big.Int // s2 - but capitalized to allow access from outside of zksigma 41 | } 42 | 43 | // NewConsistencyProof generates a proof that the r used in CM(=xG+rH) 44 | // and CMTok(=r(sk*H)) are the same. 45 | func NewConsistencyProof(zkpcp ZKPCurveParams, 46 | CM, CMTok, PubKey ECPoint, value, randomness *big.Int) (*ConsistencyProof, error) { 47 | 48 | modValue := new(big.Int).Mod(value, zkpcp.C.Params().N) 49 | //modRandom := new(big.Int).Mod(randomness, zkpcp.C.Params().N) 50 | 51 | // do a quick correctness check to ensure the value we are testing and the 52 | // randomness are correct 53 | if !CM.Equal(PedCommitR(zkpcp, value, randomness)) { 54 | return &ConsistencyProof{}, &errorProof{"ConsistencyProve", "value and randomVal does not produce CM"} 55 | } 56 | 57 | if !CMTok.Equal(zkpcp.Mult(PubKey, randomness)) { 58 | return &ConsistencyProof{}, &errorProof{"ConsistencyProve", "Pubkey and randomVal does not produce CMTok"} 59 | } 60 | 61 | u1, err := rand.Int(rand.Reader, zkpcp.C.Params().N) 62 | if err != nil { 63 | return nil, err 64 | } 65 | u2, err := rand.Int(rand.Reader, zkpcp.C.Params().N) 66 | if err != nil { 67 | return nil, err 68 | } 69 | 70 | T1 := PedCommitR(zkpcp, u1, u2) 71 | T2 := zkpcp.Mult(PubKey, u2) 72 | 73 | Challenge := GenerateChallenge(zkpcp, zkpcp.G.Bytes(), zkpcp.H.Bytes(), 74 | CM.Bytes(), CMTok.Bytes(), 75 | PubKey.Bytes(), 76 | T1.Bytes(), T2.Bytes()) 77 | 78 | s1 := new(big.Int).Add(u1, new(big.Int).Mul(modValue, Challenge)) 79 | s2 := new(big.Int).Add(u2, new(big.Int).Mul(randomness, Challenge)) 80 | 81 | s1.Mod(s1, zkpcp.C.Params().N) 82 | s2.Mod(s2, zkpcp.C.Params().N) 83 | 84 | conProof := &ConsistencyProof{T1, T2, Challenge, s1, s2} 85 | 86 | return conProof, nil 87 | 88 | } 89 | 90 | // Verify checks if a ConsistencyProof conProof is valid 91 | func (conProof *ConsistencyProof) Verify( 92 | zkpcp ZKPCurveParams, CM, CMTok, PubKey ECPoint) (bool, error) { 93 | 94 | if conProof == nil { 95 | return false, &errorProof{"ConsistencyProof.Verify", fmt.Sprintf("passed proof is nil")} 96 | } 97 | 98 | // Regenerate challenge string 99 | Challenge := GenerateChallenge(zkpcp, zkpcp.G.Bytes(), zkpcp.H.Bytes(), 100 | CM.Bytes(), CMTok.Bytes(), 101 | PubKey.Bytes(), 102 | conProof.T1.Bytes(), conProof.T2.Bytes()) 103 | 104 | // c ?= HASH(G, H, T1, T2, PK, CM, Y) 105 | if Challenge.Cmp(conProof.Challenge) != 0 { 106 | return false, &errorProof{"ConsistencyVerify", fmt.Sprintf("c comparison failed. proof: %v calculated: %v", 107 | conProof.Challenge, Challenge)} 108 | } 109 | // lhs :: left hand side, rhs :: right hand side 110 | // s1G + s2H ?= T1 + cCM, CM should be point1 111 | // s1G + s2H from how PedCommitR works 112 | lhs := PedCommitR(zkpcp, conProof.S1, conProof.S2) 113 | // cCM 114 | temp1 := zkpcp.Mult(CM, Challenge) 115 | // T1 + cCM 116 | rhs := zkpcp.Add(conProof.T1, temp1) 117 | 118 | if !lhs.Equal(rhs) { 119 | return false, &errorProof{"ConsistencyVerify", "CM check is failing"} 120 | } 121 | 122 | // s2PK ?= T2 + cY 123 | lhs = zkpcp.Mult(PubKey, conProof.S2) 124 | temp1 = zkpcp.Mult(CMTok, Challenge) 125 | rhs = zkpcp.Add(conProof.T2, temp1) 126 | 127 | if !lhs.Equal(rhs) { 128 | return false, &errorProof{"ConsistencyVerify", "CMTok check is failing"} 129 | } 130 | 131 | // All three checks passed, proof must be correct 132 | return true, nil 133 | } 134 | 135 | // Bytes returns a byte slice with a serialized representation of ConsistencyProof proof 136 | func (proof *ConsistencyProof) Bytes() []byte { 137 | var buf bytes.Buffer 138 | 139 | WriteECPoint(&buf, proof.T1) 140 | WriteECPoint(&buf, proof.T2) 141 | WriteBigInt(&buf, proof.Challenge) 142 | WriteBigInt(&buf, proof.S1) 143 | WriteBigInt(&buf, proof.S2) 144 | 145 | return buf.Bytes() 146 | } 147 | 148 | // NewConsistencyProofFromBytes returns a ConsistencyProof generated from the 149 | // deserialization of byte slice b 150 | func NewConsistencyProofFromBytes(b []byte) (*ConsistencyProof, error) { 151 | proof := new(ConsistencyProof) 152 | buf := bytes.NewBuffer(b) 153 | proof.T1, _ = ReadECPoint(buf) 154 | proof.T2, _ = ReadECPoint(buf) 155 | proof.Challenge, _ = ReadBigInt(buf) 156 | proof.S1, _ = ReadBigInt(buf) 157 | proof.S2, _ = ReadBigInt(buf) 158 | return proof, nil 159 | } 160 | -------------------------------------------------------------------------------- /btcec/pubkey.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013-2014 The btcsuite developers 2 | // Use of this source code is governed by an ISC 3 | // license that can be found in the LICENSE file. 4 | 5 | package btcec 6 | 7 | import ( 8 | "crypto/ecdsa" 9 | "errors" 10 | "fmt" 11 | "math/big" 12 | ) 13 | 14 | // These constants define the lengths of serialized public keys. 15 | const ( 16 | PubKeyBytesLenCompressed = 33 17 | PubKeyBytesLenUncompressed = 65 18 | PubKeyBytesLenHybrid = 65 19 | ) 20 | 21 | func isOdd(a *big.Int) bool { 22 | return a.Bit(0) == 1 23 | } 24 | 25 | // decompressPoint decompresses a point on the given curve given the X point and 26 | // the solution to use. 27 | func decompressPoint(curve *KoblitzCurve, x *big.Int, ybit bool) (*big.Int, error) { 28 | // TODO: This will probably only work for secp256k1 due to 29 | // optimizations. 30 | 31 | // Y = +-sqrt(x^3 + B) 32 | x3 := new(big.Int).Mul(x, x) 33 | x3.Mul(x3, x) 34 | x3.Add(x3, curve.Params().B) 35 | 36 | // now calculate sqrt mod p of x2 + B 37 | // This code used to do a full sqrt based on tonelli/shanks, 38 | // but this was replaced by the algorithms referenced in 39 | // https://bitcointalk.org/index.php?topic=162805.msg1712294#msg1712294 40 | y := new(big.Int).Exp(x3, curve.QPlus1Div4(), curve.Params().P) 41 | 42 | if ybit != isOdd(y) { 43 | y.Sub(curve.Params().P, y) 44 | } 45 | if ybit != isOdd(y) { 46 | return nil, fmt.Errorf("ybit doesn't match oddness") 47 | } 48 | return y, nil 49 | } 50 | 51 | const ( 52 | pubkeyCompressed byte = 0x2 // y_bit + x coord 53 | pubkeyUncompressed byte = 0x4 // x coord + y coord 54 | pubkeyHybrid byte = 0x6 // y_bit + x coord + y coord 55 | ) 56 | 57 | // IsCompressedPubKey returns true the the passed serialized public key has 58 | // been encoded in compressed format, and false otherwise. 59 | func IsCompressedPubKey(pubKey []byte) bool { 60 | // The public key is only compressed if it is the correct length and 61 | // the format (first byte) is one of the compressed pubkey values. 62 | return len(pubKey) == PubKeyBytesLenCompressed && 63 | (pubKey[0]&^byte(0x1) == pubkeyCompressed) 64 | } 65 | 66 | // ParsePubKey parses a public key for a koblitz curve from a bytestring into a 67 | // ecdsa.Publickey, verifying that it is valid. It supports compressed, 68 | // uncompressed and hybrid signature formats. 69 | func ParsePubKey(pubKeyStr []byte, curve *KoblitzCurve) (key *PublicKey, err error) { 70 | pubkey := PublicKey{} 71 | pubkey.Curve = curve 72 | 73 | if len(pubKeyStr) == 0 { 74 | return nil, errors.New("pubkey string is empty") 75 | } 76 | 77 | format := pubKeyStr[0] 78 | ybit := (format & 0x1) == 0x1 79 | format &= ^byte(0x1) 80 | 81 | switch len(pubKeyStr) { 82 | case PubKeyBytesLenUncompressed: 83 | if format != pubkeyUncompressed && format != pubkeyHybrid { 84 | return nil, fmt.Errorf("invalid magic in pubkey str: "+ 85 | "%d", pubKeyStr[0]) 86 | } 87 | 88 | pubkey.X = new(big.Int).SetBytes(pubKeyStr[1:33]) 89 | pubkey.Y = new(big.Int).SetBytes(pubKeyStr[33:]) 90 | // hybrid keys have extra information, make use of it. 91 | if format == pubkeyHybrid && ybit != isOdd(pubkey.Y) { 92 | return nil, fmt.Errorf("ybit doesn't match oddness") 93 | } 94 | case PubKeyBytesLenCompressed: 95 | // format is 0x2 | solution, 96 | // solution determines which solution of the curve we use. 97 | /// y^2 = x^3 + Curve.B 98 | if format != pubkeyCompressed { 99 | return nil, fmt.Errorf("invalid magic in compressed "+ 100 | "pubkey string: %d", pubKeyStr[0]) 101 | } 102 | pubkey.X = new(big.Int).SetBytes(pubKeyStr[1:33]) 103 | pubkey.Y, err = decompressPoint(curve, pubkey.X, ybit) 104 | if err != nil { 105 | return nil, err 106 | } 107 | default: // wrong! 108 | return nil, fmt.Errorf("invalid pub key length %d", 109 | len(pubKeyStr)) 110 | } 111 | 112 | if pubkey.X.Cmp(pubkey.Curve.Params().P) >= 0 { 113 | return nil, fmt.Errorf("pubkey X parameter is >= to P") 114 | } 115 | if pubkey.Y.Cmp(pubkey.Curve.Params().P) >= 0 { 116 | return nil, fmt.Errorf("pubkey Y parameter is >= to P") 117 | } 118 | if !pubkey.Curve.IsOnCurve(pubkey.X, pubkey.Y) { 119 | return nil, fmt.Errorf("pubkey isn't on secp256k1 curve") 120 | } 121 | return &pubkey, nil 122 | } 123 | 124 | // PublicKey is an ecdsa.PublicKey with additional functions to 125 | // serialize in uncompressed, compressed, and hybrid formats. 126 | type PublicKey ecdsa.PublicKey 127 | 128 | // ToECDSA returns the public key as a *ecdsa.PublicKey. 129 | func (p *PublicKey) ToECDSA() *ecdsa.PublicKey { 130 | return (*ecdsa.PublicKey)(p) 131 | } 132 | 133 | // SerializeUncompressed serializes a public key in a 65-byte uncompressed 134 | // format. 135 | func (p *PublicKey) SerializeUncompressed() []byte { 136 | b := make([]byte, 0, PubKeyBytesLenUncompressed) 137 | b = append(b, pubkeyUncompressed) 138 | b = paddedAppend(32, b, p.X.Bytes()) 139 | return paddedAppend(32, b, p.Y.Bytes()) 140 | } 141 | 142 | // SerializeCompressed serializes a public key in a 33-byte compressed format. 143 | func (p *PublicKey) SerializeCompressed() []byte { 144 | b := make([]byte, 0, PubKeyBytesLenCompressed) 145 | format := pubkeyCompressed 146 | if isOdd(p.Y) { 147 | format |= 0x1 148 | } 149 | b = append(b, format) 150 | return paddedAppend(32, b, p.X.Bytes()) 151 | } 152 | 153 | // SerializeHybrid serializes a public key in a 65-byte hybrid format. 154 | func (p *PublicKey) SerializeHybrid() []byte { 155 | b := make([]byte, 0, PubKeyBytesLenHybrid) 156 | format := pubkeyHybrid 157 | if isOdd(p.Y) { 158 | format |= 0x1 159 | } 160 | b = append(b, format) 161 | b = paddedAppend(32, b, p.X.Bytes()) 162 | return paddedAppend(32, b, p.Y.Bytes()) 163 | } 164 | 165 | // IsEqual compares this PublicKey instance to the one passed, returning true if 166 | // both PublicKeys are equivalent. A PublicKey is equivalent to another, if they 167 | // both have the same X and Y coordinate. 168 | func (p *PublicKey) IsEqual(otherPubKey *PublicKey) bool { 169 | return p.X.Cmp(otherPubKey.X) == 0 && 170 | p.Y.Cmp(otherPubKey.Y) == 0 171 | } 172 | 173 | // paddedAppend appends the src byte slice to dst, returning the new slice. 174 | // If the length of the source is smaller than the passed size, leading zero 175 | // bytes are appended to the dst slice before appending src. 176 | func paddedAppend(size uint, dst, src []byte) []byte { 177 | for i := 0; i < int(size)-len(src); i++ { 178 | dst = append(dst, 0) 179 | } 180 | return append(dst, src...) 181 | } 182 | -------------------------------------------------------------------------------- /btcec/ciphering.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2016 The btcsuite developers 2 | // Use of this source code is governed by an ISC 3 | // license that can be found in the LICENSE file. 4 | 5 | package btcec 6 | 7 | import ( 8 | "bytes" 9 | "crypto/aes" 10 | "crypto/cipher" 11 | "crypto/hmac" 12 | "crypto/rand" 13 | "crypto/sha256" 14 | "crypto/sha512" 15 | "errors" 16 | "io" 17 | ) 18 | 19 | var ( 20 | // ErrInvalidMAC occurs when Message Authentication Check (MAC) fails 21 | // during decryption. This happens because of either invalid private key or 22 | // corrupt ciphertext. 23 | ErrInvalidMAC = errors.New("invalid mac hash") 24 | 25 | // errInputTooShort occurs when the input ciphertext to the Decrypt 26 | // function is less than 134 bytes long. 27 | errInputTooShort = errors.New("ciphertext too short") 28 | 29 | // errUnsupportedCurve occurs when the first two bytes of the encrypted 30 | // text aren't 0x02CA (= 712 = secp256k1, from OpenSSL). 31 | errUnsupportedCurve = errors.New("unsupported curve") 32 | 33 | errInvalidXLength = errors.New("invalid X length, must be 32") 34 | errInvalidYLength = errors.New("invalid Y length, must be 32") 35 | errInvalidPadding = errors.New("invalid PKCS#7 padding") 36 | 37 | // 0x02CA = 714 38 | ciphCurveBytes = [2]byte{0x02, 0xCA} 39 | // 0x20 = 32 40 | ciphCoordLength = [2]byte{0x00, 0x20} 41 | ) 42 | 43 | // GenerateSharedSecret generates a shared secret based on a private key and a 44 | // public key using Diffie-Hellman key exchange (ECDH) (RFC 4753). 45 | // RFC5903 Section 9 states we should only return x. 46 | func GenerateSharedSecret(privkey *PrivateKey, pubkey *PublicKey) []byte { 47 | x, _ := pubkey.Curve.ScalarMult(pubkey.X, pubkey.Y, privkey.D.Bytes()) 48 | return x.Bytes() 49 | } 50 | 51 | // Encrypt encrypts data for the target public key using AES-256-CBC. It also 52 | // generates a private key (the pubkey of which is also in the output). The only 53 | // supported curve is secp256k1. The `structure' that it encodes everything into 54 | // is: 55 | // 56 | // struct { 57 | // // Initialization Vector used for AES-256-CBC 58 | // IV [16]byte 59 | // // Public Key: curve(2) + len_of_pubkeyX(2) + pubkeyX + 60 | // // len_of_pubkeyY(2) + pubkeyY (curve = 714) 61 | // PublicKey [70]byte 62 | // // Cipher text 63 | // Data []byte 64 | // // HMAC-SHA-256 Message Authentication Code 65 | // HMAC [32]byte 66 | // } 67 | // 68 | // The primary aim is to ensure byte compatibility with Pyelliptic. Also, refer 69 | // to section 5.8.1 of ANSI X9.63 for rationale on this format. 70 | func Encrypt(pubkey *PublicKey, in []byte) ([]byte, error) { 71 | ephemeral, err := NewPrivateKey(S256()) 72 | if err != nil { 73 | return nil, err 74 | } 75 | ecdhKey := GenerateSharedSecret(ephemeral, pubkey) 76 | derivedKey := sha512.Sum512(ecdhKey) 77 | keyE := derivedKey[:32] 78 | keyM := derivedKey[32:] 79 | 80 | paddedIn := addPKCSPadding(in) 81 | // IV + Curve params/X/Y + padded plaintext/ciphertext + HMAC-256 82 | out := make([]byte, aes.BlockSize+70+len(paddedIn)+sha256.Size) 83 | iv := out[:aes.BlockSize] 84 | if _, err = io.ReadFull(rand.Reader, iv); err != nil { 85 | return nil, err 86 | } 87 | // start writing public key 88 | pb := ephemeral.PubKey().SerializeUncompressed() 89 | offset := aes.BlockSize 90 | 91 | // curve and X length 92 | copy(out[offset:offset+4], append(ciphCurveBytes[:], ciphCoordLength[:]...)) 93 | offset += 4 94 | // X 95 | copy(out[offset:offset+32], pb[1:33]) 96 | offset += 32 97 | // Y length 98 | copy(out[offset:offset+2], ciphCoordLength[:]) 99 | offset += 2 100 | // Y 101 | copy(out[offset:offset+32], pb[33:]) 102 | offset += 32 103 | 104 | // start encryption 105 | block, err := aes.NewCipher(keyE) 106 | if err != nil { 107 | return nil, err 108 | } 109 | mode := cipher.NewCBCEncrypter(block, iv) 110 | mode.CryptBlocks(out[offset:len(out)-sha256.Size], paddedIn) 111 | 112 | // start HMAC-SHA-256 113 | hm := hmac.New(sha256.New, keyM) 114 | hm.Write(out[:len(out)-sha256.Size]) // everything is hashed 115 | copy(out[len(out)-sha256.Size:], hm.Sum(nil)) // write checksum 116 | 117 | return out, nil 118 | } 119 | 120 | // Decrypt decrypts data that was encrypted using the Encrypt function. 121 | func Decrypt(priv *PrivateKey, in []byte) ([]byte, error) { 122 | // IV + Curve params/X/Y + 1 block + HMAC-256 123 | if len(in) < aes.BlockSize+70+aes.BlockSize+sha256.Size { 124 | return nil, errInputTooShort 125 | } 126 | 127 | // read iv 128 | iv := in[:aes.BlockSize] 129 | offset := aes.BlockSize 130 | 131 | // start reading pubkey 132 | if !bytes.Equal(in[offset:offset+2], ciphCurveBytes[:]) { 133 | return nil, errUnsupportedCurve 134 | } 135 | offset += 2 136 | 137 | if !bytes.Equal(in[offset:offset+2], ciphCoordLength[:]) { 138 | return nil, errInvalidXLength 139 | } 140 | offset += 2 141 | 142 | xBytes := in[offset : offset+32] 143 | offset += 32 144 | 145 | if !bytes.Equal(in[offset:offset+2], ciphCoordLength[:]) { 146 | return nil, errInvalidYLength 147 | } 148 | offset += 2 149 | 150 | yBytes := in[offset : offset+32] 151 | offset += 32 152 | 153 | pb := make([]byte, 65) 154 | pb[0] = byte(0x04) // uncompressed 155 | copy(pb[1:33], xBytes) 156 | copy(pb[33:], yBytes) 157 | // check if (X, Y) lies on the curve and create a Pubkey if it does 158 | pubkey, err := ParsePubKey(pb, S256()) 159 | if err != nil { 160 | return nil, err 161 | } 162 | 163 | // check for cipher text length 164 | if (len(in)-aes.BlockSize-offset-sha256.Size)%aes.BlockSize != 0 { 165 | return nil, errInvalidPadding // not padded to 16 bytes 166 | } 167 | 168 | // read hmac 169 | messageMAC := in[len(in)-sha256.Size:] 170 | 171 | // generate shared secret 172 | ecdhKey := GenerateSharedSecret(priv, pubkey) 173 | derivedKey := sha512.Sum512(ecdhKey) 174 | keyE := derivedKey[:32] 175 | keyM := derivedKey[32:] 176 | 177 | // verify mac 178 | hm := hmac.New(sha256.New, keyM) 179 | hm.Write(in[:len(in)-sha256.Size]) // everything is hashed 180 | expectedMAC := hm.Sum(nil) 181 | if !hmac.Equal(messageMAC, expectedMAC) { 182 | return nil, ErrInvalidMAC 183 | } 184 | 185 | // start decryption 186 | block, err := aes.NewCipher(keyE) 187 | if err != nil { 188 | return nil, err 189 | } 190 | mode := cipher.NewCBCDecrypter(block, iv) 191 | // same length as ciphertext 192 | plaintext := make([]byte, len(in)-offset-sha256.Size) 193 | mode.CryptBlocks(plaintext, in[offset:len(in)-sha256.Size]) 194 | 195 | return removePKCSPadding(plaintext) 196 | } 197 | 198 | // Implement PKCS#7 padding with block size of 16 (AES block size). 199 | 200 | // addPKCSPadding adds padding to a block of data 201 | func addPKCSPadding(src []byte) []byte { 202 | padding := aes.BlockSize - len(src)%aes.BlockSize 203 | padtext := bytes.Repeat([]byte{byte(padding)}, padding) 204 | return append(src, padtext...) 205 | } 206 | 207 | // removePKCSPadding removes padding from data that was added with addPKCSPadding 208 | func removePKCSPadding(src []byte) ([]byte, error) { 209 | length := len(src) 210 | padLength := int(src[length-1]) 211 | if padLength > aes.BlockSize || length < aes.BlockSize { 212 | return nil, errInvalidPadding 213 | } 214 | 215 | return src[:length-padLength], nil 216 | } 217 | -------------------------------------------------------------------------------- /disjunctive.go: -------------------------------------------------------------------------------- 1 | package zksigma 2 | 3 | import ( 4 | "bytes" 5 | "crypto/rand" 6 | "fmt" 7 | "math/big" 8 | ) 9 | 10 | // DisjunctiveProof is a proof that you know either x or y but does not reveal 11 | // which one you know 12 | // 13 | // Public: generator points G and H, A, B 14 | // 15 | // Prover Verifier 16 | // ====== ======== 17 | // (proving x) 18 | // knows x AND/OR y 19 | // A = xG; B = yH or yG learns A, B 20 | // selects random u1, u2, u3 21 | // T1 = u1G 22 | // T2 = u2H + (-u3)yH 23 | // c = HASH(T1, T2, G, A, B) 24 | // deltaC = c - u3 25 | // s = u1 + deltaC * x 26 | // T1, T2, c, deltaC, u3, s, u2 -MAP-> T1, T2, c, c1, c2, s1, s2 27 | // c ?= HASH(T1, T2, G, A, B) 28 | // c ?= c1 + c2 // mod zkpcp.C.Params().N 29 | // s1G ?= T1 + c1A 30 | // s2G ?= T2 + c2A 31 | // To prove y instead: 32 | // 33 | // Prover Verifier 34 | // ====== ======== 35 | // T2, T1, c, u3, deltaC, u2, s -MAP-> T1, T2, c, c1, c2, s1, s2 36 | // Same checks as above 37 | // 38 | // Note: 39 | // It should be indistinguishable for Verifier with T1, T2, c, c1, c2, s1, s2 40 | // to tell if we are proving x or y. The above arrows show how the variables 41 | // used in the proof translate to T1, T2, etc. 42 | // 43 | // More info: https://drive.google.com/file/d/0B_ndzgLH0bcvMjg3M1ROUWQwWTBCN0loQ055T212eV9JRU1v/view 44 | // see section 4.2 45 | type DisjunctiveProof struct { 46 | T1 ECPoint 47 | T2 ECPoint 48 | C *big.Int 49 | C1 *big.Int 50 | C2 *big.Int 51 | S1 *big.Int 52 | S2 *big.Int 53 | } 54 | 55 | // NewDisjunctiveProof generates a disjunctive proof. Base1 and Base2 are our chosen base points. 56 | // Result1 is Base1 multiplied by x or y, and Result2 is Base2 multiplied by x or y. x is the value to 57 | // prove, if option is Left, we use Base1 and Result1 - if option is Right we use Base2 and Result2. The 58 | // verifier will not learn what side is being proved and should not be able to tell. 59 | func NewDisjunctiveProof( 60 | zkpcp ZKPCurveParams, Base1, Result1, Base2, Result2 ECPoint, x *big.Int, option Side) (*DisjunctiveProof, error) { 61 | 62 | modValue := new(big.Int).Mod(x, zkpcp.C.Params().N) 63 | 64 | // Declaring them like this because Golang crys otherwise 65 | var ProveBase, ProveResult, OtherBase, OtherResult ECPoint 66 | 67 | // Generate a proof for A 68 | if option == Left { 69 | ProveBase = Base1 70 | ProveResult = Result1 71 | OtherBase = Base2 72 | OtherResult = Result2 73 | } else if option == Right { // Generate a proof for B 74 | ProveBase = Base2 75 | ProveResult = Result2 76 | OtherBase = Base1 77 | OtherResult = Result1 78 | } else { // number for option is not correct 79 | return &DisjunctiveProof{}, &errorProof{"DisjunctiveProve", "invalid side provided"} 80 | } 81 | 82 | if !zkpcp.Mult(ProveBase, x).Equal(ProveResult) { 83 | return &DisjunctiveProof{}, &errorProof{"DisjunctiveProve", "Base and Result to be proved not related by x"} 84 | } 85 | u1, err := rand.Int(rand.Reader, zkpcp.C.Params().N) 86 | if err != nil { 87 | return nil, err 88 | } 89 | u2, err := rand.Int(rand.Reader, zkpcp.C.Params().N) 90 | if err != nil { 91 | return nil, err 92 | } 93 | u3, err := rand.Int(rand.Reader, zkpcp.C.Params().N) 94 | if err != nil { 95 | return nil, err 96 | } 97 | 98 | // for (-u3)yH 99 | u3Neg := new(big.Int).Neg(u3) 100 | u3Neg.Mod(u3Neg, zkpcp.C.Params().N) 101 | 102 | // T1 = u1G 103 | T1 := zkpcp.Mult(ProveBase, u1) 104 | 105 | // u2H 106 | temp := zkpcp.Mult(OtherBase, u2) 107 | // (-u3)yH 108 | temp2 := zkpcp.Mult(OtherResult, u3Neg) 109 | // T2 = u2H + (-u3)yH (yH is OtherResult) 110 | T2 := zkpcp.Add(temp, temp2) 111 | 112 | var Challenge *big.Int 113 | if option == 0 { 114 | // String for proving Base1 and Result1 115 | Challenge = GenerateChallenge(zkpcp, Base1.Bytes(), Result1.Bytes(), 116 | Base2.Bytes(), Result2.Bytes(), 117 | T1.Bytes(), T2.Bytes()) 118 | } else { 119 | 120 | // If we are proving Base2 and Result2 then we must switch T1 and 121 | // T2 in this string, look at mapping in proof for clarification 122 | Challenge = GenerateChallenge(zkpcp, Base1.Bytes(), Result1.Bytes(), 123 | Base2.Bytes(), Result2.Bytes(), 124 | T2.Bytes(), T1.Bytes()) //T2 and T1 SWAPPED! 125 | } 126 | 127 | deltaC := new(big.Int).Sub(Challenge, u3) 128 | deltaC.Mod(deltaC, zkpcp.C.Params().N) 129 | 130 | s := new(big.Int).Add(u1, new(big.Int).Mul(deltaC, modValue)) 131 | 132 | // Look at mapping given in block comment above 133 | if option == Left { 134 | return &DisjunctiveProof{ 135 | T1, 136 | T2, 137 | Challenge, 138 | deltaC, 139 | u3, 140 | s, 141 | u2}, nil 142 | } 143 | 144 | return &DisjunctiveProof{ 145 | T2, 146 | T1, 147 | Challenge, 148 | u3, 149 | deltaC, 150 | u2, 151 | s}, nil 152 | } 153 | 154 | // Verify checks if DisjunctiveProof djProof is valid for the given bases and results 155 | func (djProof *DisjunctiveProof) Verify( 156 | zkpcp ZKPCurveParams, Base1, Result1, Base2, Result2 ECPoint) (bool, error) { 157 | 158 | if djProof == nil { 159 | return false, &errorProof{"DisjunctiveProof.Verify", fmt.Sprintf("passed proof is nil")} 160 | } 161 | 162 | T1 := djProof.T1 163 | T2 := djProof.T2 164 | C := djProof.C 165 | C1 := djProof.C1 166 | C2 := djProof.C2 167 | S1 := djProof.S1 168 | S2 := djProof.S2 169 | 170 | checkC := GenerateChallenge(zkpcp, Base1.Bytes(), Result1.Bytes(), 171 | Base2.Bytes(), Result2.Bytes(), 172 | T1.Bytes(), T2.Bytes()) 173 | 174 | if checkC.Cmp(C) != 0 { 175 | return false, &errorProof{"DisjunctiveVerify", "checkC does not agree with proofC"} 176 | } 177 | 178 | // C1 + C2 179 | totalC := new(big.Int).Add(C1, C2) 180 | totalC.Mod(totalC, zkpcp.C.Params().N) 181 | if totalC.Cmp(C) != 0 { 182 | return false, &errorProof{"DisjunctiveVerify", "totalC does not agree with proofC"} 183 | } 184 | 185 | // T1 + c1A 186 | c1A := zkpcp.Mult(Result1, C1) 187 | checks1G := zkpcp.Add(T1, c1A) 188 | s1G := zkpcp.Mult(Base1, S1) 189 | 190 | if !checks1G.Equal(s1G) { 191 | return false, &errorProof{"DisjunctiveVerify", "s1G not equal to T1 + c1A"} 192 | } 193 | 194 | // T2 + c2B 195 | c2A := zkpcp.Mult(Result2, C2) 196 | checks2G := zkpcp.Add(c2A, T2) 197 | s2G := zkpcp.Mult(Base2, S2) 198 | 199 | if !checks2G.Equal(s2G) { 200 | return false, &errorProof{"DisjunctiveVerify", "s2G not equal to T2 + c2B"} 201 | } 202 | 203 | return true, nil 204 | } 205 | 206 | // Bytes returns a byte slice with a serialized representation of DisjunctiveProof proof 207 | func (djProof *DisjunctiveProof) Bytes() []byte { 208 | var buf bytes.Buffer 209 | 210 | WriteECPoint(&buf, djProof.T1) 211 | WriteECPoint(&buf, djProof.T2) 212 | WriteBigInt(&buf, djProof.C) 213 | WriteBigInt(&buf, djProof.C1) 214 | WriteBigInt(&buf, djProof.C2) 215 | WriteBigInt(&buf, djProof.S1) 216 | WriteBigInt(&buf, djProof.S2) 217 | 218 | return buf.Bytes() 219 | } 220 | 221 | // NewDisjunctiveProofFromBytes returns a DisjunctiveProof generated from the 222 | // deserialization of byte slice b 223 | func NewDisjunctiveProofFromBytes(b []byte) (*DisjunctiveProof, error) { 224 | proof := new(DisjunctiveProof) 225 | buf := bytes.NewBuffer(b) 226 | proof.T1, _ = ReadECPoint(buf) 227 | proof.T2, _ = ReadECPoint(buf) 228 | proof.C, _ = ReadBigInt(buf) 229 | proof.C1, _ = ReadBigInt(buf) 230 | proof.C2, _ = ReadBigInt(buf) 231 | proof.S1, _ = ReadBigInt(buf) 232 | proof.S2, _ = ReadBigInt(buf) 233 | return proof, nil 234 | } 235 | -------------------------------------------------------------------------------- /crypto.go: -------------------------------------------------------------------------------- 1 | package zksigma 2 | 3 | import ( 4 | "crypto/elliptic" 5 | "crypto/rand" 6 | "crypto/sha256" 7 | "flag" 8 | "fmt" 9 | "io" 10 | "log" 11 | "math/big" 12 | 13 | "github.com/mit-dci/zksigma/btcec" 14 | "github.com/mit-dci/zksigma/wire" 15 | ) 16 | 17 | // ZKPCurveParams is zero knowledge proof curve and params struct, only one instance should be used 18 | type ZKPCurveParams struct { 19 | C elliptic.Curve // Curve 20 | G ECPoint // generator 1 21 | H ECPoint // generator 2 22 | HPoints []ECPoint // HPoints should be initialized with a pre-populated array of the ZKCurve's generator point H multiplied by 2^x where x = [0...63] 23 | } 24 | 25 | // DEBUG Indicates whether we output debug information while running the tests. Default off. 26 | var DEBUG = flag.Bool("debug1", false, "Debug output") 27 | 28 | type errorProof struct { 29 | t string // proof type that failed 30 | s string // error message 31 | } 32 | 33 | func (e *errorProof) Error() string { 34 | return fmt.Sprintf("%v - %v\n", e.t, e.s) 35 | } 36 | 37 | func proofStatus(e *errorProof) int { 38 | if *DEBUG && e != nil { 39 | fmt.Printf("ERROR: %v \n", e.Error()) 40 | return -1 41 | } 42 | return 0 43 | } 44 | 45 | func logStuff(format string, args ...interface{}) { 46 | if *DEBUG { 47 | log.SetFlags(log.Lshortfile) 48 | log.Printf(format, args...) 49 | } 50 | } 51 | 52 | // == Keygen == 53 | 54 | func KeyGen(curve elliptic.Curve, base ECPoint) (ECPoint, *big.Int) { 55 | 56 | sk, err := rand.Int(rand.Reader, curve.Params().N) 57 | if err != nil { 58 | panic(err) 59 | } 60 | pkX, pkY := curve.ScalarMult(base.X, base.Y, sk.Bytes()) 61 | 62 | return ECPoint{pkX, pkY}, sk 63 | } 64 | 65 | // BigZero contains a cached instance of big.Int with value 0 66 | var BigZero *big.Int 67 | 68 | // ============ ECPoint OPERATIONS ================== 69 | 70 | type ECPoint struct { 71 | X, Y *big.Int 72 | } 73 | 74 | // Zero is a cached variable containing ECPoint{big.NewInt(0), big.NewInt(0)} 75 | var Zero ECPoint // initialized in init() 76 | 77 | // Equal returns true if points p (self) and p2 (arg) are the same. 78 | func (p ECPoint) Equal(p2 ECPoint) bool { 79 | if p.X.Cmp(p2.X) == 0 && p2.Y.Cmp(p2.Y) == 0 { 80 | return true 81 | } 82 | return false 83 | } 84 | 85 | // Mult multiplies point p by scalar s and returns the resulting point 86 | func (zkpcp ZKPCurveParams) Mult(p ECPoint, s *big.Int) ECPoint { 87 | 88 | if p.X == nil && p.Y == nil { // Multiplying a nil point is "pointless". ha. 89 | return ECPoint{nil, nil} 90 | } 91 | 92 | modS := new(big.Int).Mod(s, zkpcp.C.Params().N) 93 | 94 | // if p.Equal(Zero) { 95 | // logStuff("Mult: Trying to multiple with zero-point!\n") 96 | // return p 97 | // } else 98 | if p.Equal(zkpcp.G) { 99 | X, Y := zkpcp.C.ScalarBaseMult(modS.Bytes()) 100 | return ECPoint{X, Y} 101 | } 102 | 103 | if p.Equal(zkpcp.H) { 104 | X, Y := zkpcp.C.(*btcec.KoblitzCurve).ScalarBaseMultH(modS.Bytes()) 105 | return ECPoint{X, Y} 106 | } 107 | 108 | X, Y := zkpcp.C.ScalarMult(p.X, p.Y, modS.Bytes()) 109 | return ECPoint{X, Y} 110 | } 111 | 112 | // Add adds points p and p2 and returns the resulting point 113 | func (zkpcp ZKPCurveParams) Add(p, p2 ECPoint) ECPoint { 114 | // if p.Equal(Zero) && p2.Equal(Zero) { 115 | // return Zero 116 | // } else 117 | if p.Equal(Zero) && zkpcp.C.IsOnCurve(p2.X, p2.Y) { 118 | return p2 119 | } else if p2.Equal(Zero) && zkpcp.C.IsOnCurve(p.X, p.Y) { 120 | return p 121 | } 122 | 123 | X, Y := zkpcp.C.Add(p.X, p.Y, p2.X, p2.Y) 124 | 125 | return ECPoint{X, Y} 126 | } 127 | 128 | func (zkpcp ZKPCurveParams) Sub(p, p2 ECPoint) ECPoint { 129 | // if p.Equal(Zero) && p2.Equal(Zero) { 130 | // return Zero 131 | // } else 132 | if p.Equal(Zero) && zkpcp.C.IsOnCurve(p2.X, p2.Y) { 133 | return zkpcp.Neg(p2) 134 | } else if p2.Equal(Zero) && zkpcp.C.IsOnCurve(p.X, p.Y) { 135 | return p 136 | } 137 | 138 | temp := zkpcp.Neg(p2) 139 | X, Y := zkpcp.C.Add(p.X, p.Y, temp.X, temp.Y) 140 | 141 | return ECPoint{X, Y} 142 | } 143 | 144 | // Neg returns the additive inverse of point p 145 | func (zkpcp ZKPCurveParams) Neg(p ECPoint) ECPoint { 146 | negY := new(big.Int).Neg(p.Y) 147 | modValue := new(big.Int).Mod(negY, zkpcp.C.Params().P) 148 | return ECPoint{p.X, modValue} 149 | } 150 | 151 | func (p ECPoint) Bytes() []byte { 152 | return append(p.X.Bytes(), p.Y.Bytes()...) 153 | } 154 | 155 | // WriteECPoint write an ECPoint to io.Writer w 156 | func WriteECPoint(w io.Writer, p ECPoint) error { 157 | err := wire.WriteVarBytes(w, p.X.Bytes()) 158 | if err != nil { 159 | return err 160 | } 161 | err = wire.WriteVarBytes(w, p.Y.Bytes()) 162 | return err 163 | } 164 | 165 | // ReadECPoint reads an ECPoint from io.Reader r 166 | func ReadECPoint(r io.Reader) (ECPoint, error) { 167 | xBytes, err := wire.ReadVarBytes(r, 32, "x") 168 | if err != nil { 169 | return Zero, err 170 | } 171 | yBytes, err := wire.ReadVarBytes(r, 32, "y") 172 | if err != nil { 173 | return Zero, err 174 | } 175 | return ECPoint{X: big.NewInt(0).SetBytes(xBytes), Y: big.NewInt(0).SetBytes(yBytes)}, nil 176 | } 177 | 178 | // WriteBigInt write a big.Int to io.Writer w 179 | func WriteBigInt(w io.Writer, b *big.Int) error { 180 | neg := []byte{0x00} 181 | if b.Sign() < 0 { 182 | neg = []byte{0x01} 183 | } 184 | err := wire.WriteVarBytes(w, append(neg, b.Bytes()...)) 185 | return err 186 | } 187 | 188 | // ReadBigInt reads a big.Int from io.Reader r 189 | func ReadBigInt(r io.Reader) (*big.Int, error) { 190 | bBytes, err := wire.ReadVarBytes(r, 32, "") 191 | if err != nil { 192 | return nil, err 193 | } 194 | newInt := big.NewInt(0).SetBytes(bBytes[1:]) 195 | if bBytes[0] == 0x01 { 196 | newInt.Neg(newInt) 197 | } 198 | return newInt, nil 199 | } 200 | 201 | // CommitR uses the Public Key (pk) and a random number (r) to 202 | // generate a commitment of r as an ECPoint 203 | func CommitR(zkpcp ZKPCurveParams, pk ECPoint, r *big.Int) ECPoint { 204 | newR := new(big.Int).Mod(r, zkpcp.C.Params().N) 205 | X, Y := zkpcp.C.ScalarMult(pk.X, pk.Y, newR.Bytes()) // {commitR.X,commitR.Y} = newR * {pk.X, pk.Y} 206 | return ECPoint{X, Y} 207 | } 208 | 209 | // VerifyR checks if the point in question is a valid commitment of r 210 | // by generating a new point and comparing the two 211 | func VerifyR(zkpcp ZKPCurveParams, rt ECPoint, pk ECPoint, r *big.Int) bool { 212 | p := CommitR(zkpcp, pk, r) // Generate test point (P) using pk and r 213 | return p.Equal(rt) 214 | } 215 | 216 | // =============== PEDERSEN COMMITMENTS ================ 217 | // PedCommit generates a pedersen commitment of value using the 218 | // generators of zkpcp. It returns the randomness generated for the 219 | // commitment. 220 | func PedCommit(zkpcp ZKPCurveParams, value *big.Int) (ECPoint, *big.Int, error) { 221 | // randomValue = rand() mod N 222 | randomValue, err := rand.Int(rand.Reader, zkpcp.C.Params().N) 223 | if err != nil { 224 | return Zero, nil, err 225 | } 226 | return PedCommitR(zkpcp, value, randomValue), randomValue, nil 227 | } 228 | 229 | // PedCommitR generates a Pedersen commitment with a given random value 230 | func PedCommitR(zkpcp ZKPCurveParams, value, randomValue *big.Int) ECPoint { 231 | 232 | // modValue = value mod N 233 | modValue := new(big.Int).Mod(value, zkpcp.C.Params().N) 234 | modRandom := new(big.Int).Mod(randomValue, zkpcp.C.Params().N) 235 | 236 | // mG, rH :: lhs, rhs 237 | lhs := zkpcp.Mult(zkpcp.G, modValue) 238 | rhs := zkpcp.Mult(zkpcp.H, modRandom) 239 | 240 | //mG + rH 241 | return zkpcp.Add(lhs, rhs) 242 | } 243 | 244 | // Open checks if the values given result in the given Pedersen commitment 245 | func Open(zkpcp ZKPCurveParams, value, randomValue *big.Int, pcomm ECPoint) bool { 246 | return PedCommitR(zkpcp, value, randomValue).Equal(pcomm) 247 | 248 | } 249 | 250 | // ====== Generalized Hash Function ========= 251 | 252 | // GenerateChallenge hashes the passed byte arrays using SHA-256, and then returns 253 | // the resulting hash as a big.Int modulo the order of the curve base point 254 | func GenerateChallenge(zkpcp ZKPCurveParams, arr ...[]byte) *big.Int { 255 | hasher := sha256.New() 256 | for _, v := range arr { 257 | hasher.Write(v) 258 | } 259 | c := new(big.Int).SetBytes(hasher.Sum(nil)) 260 | c = new(big.Int).Mod(c, zkpcp.C.Params().N) 261 | return c 262 | } 263 | 264 | // ====== init ========= 265 | 266 | func init() { 267 | 268 | BigZero = big.NewInt(0) 269 | Zero = ECPoint{BigZero, BigZero} 270 | 271 | } 272 | -------------------------------------------------------------------------------- /abc_test.go: -------------------------------------------------------------------------------- 1 | package zksigma 2 | 3 | import ( 4 | "crypto/rand" 5 | "math/big" 6 | "testing" 7 | ) 8 | 9 | // TestABCProof tests if the ABC Proof can generate and verify. 10 | func TestABCProof(t *testing.T) { 11 | sk, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 12 | value, _ := rand.Int(rand.Reader, big.NewInt(10000000000)) // "realistic rarnge" 13 | ua, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 14 | 15 | PK := TestCurve.Mult(TestCurve.H, sk) 16 | A := TestCurve.Mult(TestCurve.H, ua) // uaH 17 | temp := TestCurve.Mult(TestCurve.G, value) // value(G) 18 | 19 | // A = vG + uaH 20 | A = TestCurve.Add(A, temp) 21 | AToken := TestCurve.Mult(PK, ua) 22 | 23 | aProof, status := NewABCProof(TestCurve, A, AToken, value, sk, Right) 24 | 25 | if status != nil { 26 | proofStatus(status.(*errorProof)) 27 | t.Logf("ABCProof RIGHT failed to generate!\n") 28 | t.Fatalf("ABCProof RIGHT failed\n") 29 | } 30 | 31 | check, err := aProof.Verify(TestCurve, A, AToken) 32 | if !check || err != nil { 33 | t.Logf("ABCProof RIGHT Failed to verify!\n") 34 | t.Fatalf("ABCVerify RIGHT failed\n") 35 | } 36 | 37 | A = TestCurve.Mult(TestCurve.H, ua) 38 | aProof, status = NewABCProof(TestCurve, A, AToken, big.NewInt(0), sk, Left) 39 | 40 | if status != nil { 41 | proofStatus(status.(*errorProof)) 42 | t.Logf("ABCProof LEFT failed to generate!\n") 43 | t.Fatalf("ABCProof LEFT failed\n") 44 | } 45 | 46 | check, err = aProof.Verify(TestCurve, A, AToken) 47 | if !check || err != nil { 48 | t.Logf("ABCProof LEFT Failed to verify!\n") 49 | t.Fatalf("ABCVerify LEFT failed\n") 50 | } 51 | 52 | A, ua, err = PedCommit(TestCurve, big.NewInt(1000)) 53 | if err != nil { 54 | t.Fatalf("%v\n", err) 55 | } 56 | 57 | AToken = TestCurve.Mult(PK, ua) 58 | 59 | aProof, status = NewABCProof(TestCurve, A, AToken, big.NewInt(1001), sk, Right) 60 | 61 | if status != nil { 62 | t.Logf("False proof generation succeeded! (bad)\n") 63 | t.Fatalf("ABCProve generated for false proof\n") 64 | } 65 | 66 | t.Logf("Next ABCVerify should catch false proof\n") 67 | 68 | check, err = aProof.Verify(TestCurve, A, AToken) 69 | if check || err == nil { 70 | t.Logf("ABCVerify: should have failed on false proof check!\n") 71 | t.Fatalf("ABCVerify: not working...\n") 72 | } 73 | } 74 | 75 | // TestABCProofSerialization tests if the ABC Proof can generate, serialize, deserialize, and then verify. 76 | func TestABCProofSerialization(t *testing.T) { 77 | 78 | sk, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 79 | value, _ := rand.Int(rand.Reader, big.NewInt(10000000000)) // "realistic rarnge" 80 | ua, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 81 | 82 | PK := TestCurve.Mult(TestCurve.H, sk) 83 | A := TestCurve.Mult(TestCurve.H, ua) // uaH 84 | temp := TestCurve.Mult(TestCurve.G, value) // value(G) 85 | 86 | // A = vG + uaH 87 | A = TestCurve.Add(A, temp) 88 | AToken := TestCurve.Mult(PK, ua) 89 | 90 | aProof, status := NewABCProof(TestCurve, A, AToken, value, sk, Right) 91 | 92 | if status != nil { 93 | proofStatus(status.(*errorProof)) 94 | t.Logf("ABCProof RIGHT failed to generate!\n") 95 | t.Fatalf("ABCProof RIGHT failed\n") 96 | } 97 | aProof, status = NewABCProofFromBytes(aProof.Bytes()) 98 | 99 | if status != nil { 100 | proofStatus(status.(*errorProof)) 101 | t.Fatalf("ABCProof failed to deserialize!\n") 102 | } 103 | 104 | check, err := aProof.Verify(TestCurve, A, AToken) 105 | if !check || err != nil { 106 | t.Fatalf("ABCVerify failed: %s\n", err.Error()) 107 | } 108 | } 109 | 110 | // TestBreakABCProve tests if the ABC Proof can will catch invalid proofs. 111 | func TestBreakABCProve(t *testing.T) { 112 | sk, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 113 | value, _ := rand.Int(rand.Reader, big.NewInt(10000000000)) // "realistic rarnge" 114 | ua, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 115 | 116 | PK := TestCurve.Mult(TestCurve.H, sk) 117 | CM := TestCurve.Mult(TestCurve.H, ua) // uaH 118 | temp := TestCurve.Mult(TestCurve.G, value) // value(G) 119 | 120 | // A = vG + uaH 121 | CM = TestCurve.Add(CM, temp) 122 | CMTok := TestCurve.Mult(PK, ua) 123 | 124 | u1, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 125 | u2, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 126 | u3, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 127 | ub, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 128 | uc, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 129 | 130 | B := ECPoint{} 131 | C := ECPoint{} 132 | CToken := TestCurve.Mult(TestCurve.H, uc) 133 | 134 | // B = 2/v 135 | x := new(big.Int).ModInverse(value, TestCurve.C.Params().N) 136 | B = PedCommitR(TestCurve, new(big.Int).Mul(big.NewInt(2), x), ub) 137 | 138 | // C = 2G + ucH, the 2 here is the big deal 139 | C = PedCommitR(TestCurve, big.NewInt(2), uc) 140 | 141 | disjuncAC, _ := NewDisjunctiveProof(TestCurve, CMTok, CM, TestCurve.H, TestCurve.Sub(C, TestCurve.Mult(TestCurve.G, big.NewInt(2))), uc, Right) 142 | 143 | // CMTok is Ta for the rest of the proof 144 | // T1 = u1G + u2Ta 145 | // u1G 146 | u1G := TestCurve.Mult(TestCurve.G, u1) 147 | // u2Ta 148 | u2Ta := TestCurve.Mult(CMTok, u2) 149 | // Sum the above two 150 | T1X, T1Y := TestCurve.C.Add(u1G.X, u1G.Y, u2Ta.X, u2Ta.Y) 151 | 152 | // T2 = u1B + u3H 153 | // u1B 154 | u1B := TestCurve.Mult(B, u1) 155 | // u3H 156 | u3H := TestCurve.Mult(TestCurve.H, u3) 157 | // Sum of the above two 158 | T2X, T2Y := TestCurve.C.Add(u1B.X, u1B.Y, u3H.X, u3H.Y) 159 | 160 | // c = HASH(G,H,CM,CMTok,B,C,T1,T2) 161 | Challenge := GenerateChallenge(TestCurve, TestCurve.G.Bytes(), TestCurve.H.Bytes(), 162 | CM.Bytes(), CMTok.Bytes(), 163 | B.Bytes(), C.Bytes(), 164 | T1X.Bytes(), T1Y.Bytes(), 165 | T2X.Bytes(), T2Y.Bytes()) 166 | 167 | // j = u1 + v * c , can be though of as s1 168 | j := new(big.Int).Add(u1, new(big.Int).Mul(value, Challenge)) 169 | j = new(big.Int).Mod(j, TestCurve.C.Params().N) 170 | 171 | // k = u2 + inv(sk) * c 172 | // inv(sk) 173 | isk := new(big.Int).ModInverse(sk, TestCurve.C.Params().N) 174 | k := new(big.Int).Add(u2, new(big.Int).Mul(isk, Challenge)) 175 | k = new(big.Int).Mod(k, TestCurve.C.Params().N) 176 | 177 | // l = u3 + (uc - v * ub) * c 178 | temp1 := new(big.Int).Sub(uc, new(big.Int).Mul(value, ub)) 179 | l := new(big.Int).Add(u3, new(big.Int).Mul(temp1, Challenge)) 180 | 181 | evilProof := &ABCProof{ 182 | B, 183 | C, 184 | ECPoint{T1X, T1Y}, 185 | ECPoint{T2X, T2Y}, 186 | Challenge, 187 | j, k, l, CToken, 188 | disjuncAC} 189 | 190 | t.Logf("Attempting to pass malicious true proof into verification function\n") 191 | t.Logf("This test should throw a couple error messages in debug\n") 192 | 193 | check, err := evilProof.Verify(TestCurve, CM, CMTok) 194 | if check || err == nil { 195 | t.Logf("ABCVerify - EVIL: accepted attack input! c = 2, should fail...\n") 196 | t.Fatalf("ABCVerify - EVIL: failed to catch attack!\n") 197 | } 198 | } 199 | 200 | func BenchmarkABCProve_0(b *testing.B) { 201 | value := big.NewInt(0) 202 | 203 | sk, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 204 | PK := TestCurve.Mult(TestCurve.H, sk) 205 | 206 | CM, randVal, err := PedCommit(TestCurve, value) 207 | if err != nil { 208 | b.Fatalf("%v\n", err) 209 | } 210 | 211 | CMTok := TestCurve.Mult(PK, randVal) 212 | 213 | b.ResetTimer() 214 | for ii := 0; ii < b.N; ii++ { 215 | NewABCProof(TestCurve, CM, CMTok, value, sk, Left) 216 | } 217 | } 218 | 219 | func BenchmarkABCProve_1(b *testing.B) { 220 | value, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 221 | 222 | sk, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 223 | PK := TestCurve.Mult(TestCurve.H, sk) 224 | 225 | CM, randVal, err := PedCommit(TestCurve, value) 226 | if err != nil { 227 | b.Fatalf("%v\n", err) 228 | } 229 | 230 | CMTok := TestCurve.Mult(PK, randVal) 231 | 232 | b.ResetTimer() 233 | for ii := 0; ii < b.N; ii++ { 234 | NewABCProof(TestCurve, CM, CMTok, value, sk, Right) 235 | } 236 | } 237 | 238 | func BenchmarkABCVerify_0(b *testing.B) { 239 | value := big.NewInt(0) 240 | 241 | sk, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 242 | PK := TestCurve.Mult(TestCurve.H, sk) 243 | 244 | CM, randVal, err := PedCommit(TestCurve, value) 245 | if err != nil { 246 | b.Fatalf("%v\n", err) 247 | } 248 | 249 | CMTok := TestCurve.Mult(PK, randVal) 250 | proof, _ := NewABCProof(TestCurve, CM, CMTok, value, sk, Left) 251 | b.ResetTimer() 252 | for ii := 0; ii < b.N; ii++ { 253 | proof.Verify(TestCurve, CM, CMTok) 254 | } 255 | } 256 | 257 | func BenchmarkABCVerify_1(b *testing.B) { 258 | value, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 259 | 260 | sk, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 261 | PK := TestCurve.Mult(TestCurve.H, sk) 262 | 263 | CM, randVal, err := PedCommit(TestCurve, value) 264 | if err != nil { 265 | b.Fatalf("%v\n", err) 266 | } 267 | 268 | CMTok := TestCurve.Mult(PK, randVal) 269 | proof, _ := NewABCProof(TestCurve, CM, CMTok, value, sk, Right) 270 | b.ResetTimer() 271 | for ii := 0; ii < b.N; ii++ { 272 | proof.Verify(TestCurve, CM, CMTok) 273 | } 274 | } 275 | -------------------------------------------------------------------------------- /btcec/gensecp256k1.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014-2015 The btcsuite developers 2 | // Use of this source code is governed by an ISC 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file is ignored during the regular build due to the following build tag. 6 | // This build tag is set during go generate. 7 | // +build gensecp256k1 8 | 9 | package btcec 10 | 11 | // References: 12 | // [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone) 13 | 14 | import ( 15 | "crypto/sha256" 16 | "encoding/binary" 17 | "log" 18 | "math/big" 19 | ) 20 | 21 | // secp256k1BytePoints are dummy points used so the code which generates the 22 | // real values can compile. 23 | var secp256k1BytePoints = "" 24 | var secp256k1BytePointsH = "" 25 | 26 | // getDoublingPoints returns all the possible G^(2^i) for i in 27 | // 0..n-1 where n is the curve's bit size (256 in the case of secp256k1) 28 | // the coordinates are recorded as Jacobian coordinates. 29 | func (curve *KoblitzCurve) getDoublingPoints() [][3]fieldVal { 30 | doublingPoints := make([][3]fieldVal, curve.BitSize) 31 | 32 | // initialize px, py, pz to the Jacobian coordinates for the base point 33 | px, py := curve.bigAffineToField(curve.Gx, curve.Gy) 34 | pz := new(fieldVal).SetInt(1) 35 | for i := 0; i < curve.BitSize; i++ { 36 | doublingPoints[i] = [3]fieldVal{*px, *py, *pz} 37 | // P = 2*P 38 | curve.doubleJacobian(px, py, pz, px, py, pz) 39 | } 40 | return doublingPoints 41 | } 42 | 43 | // getDoublingPointsH returns all the possible H^(2^i) for i in 44 | // 0..n-1 where n is the curve's bit size (256 in the case of secp256k1) 45 | // the coordinates are recorded as Jacobian coordinates. 46 | // 47 | // H comes from whatever Willy does in crypto.go. 48 | func (curve *KoblitzCurve) getDoublingPointsH() [][3]fieldVal { 49 | curValue := curve.Gx 50 | s256 := sha256.New() 51 | s256.Write(new(big.Int).Add(curValue, big.NewInt(2)).Bytes()) // hash G_x + 2 which 52 | 53 | potentialXValue := make([]byte, 33) 54 | binary.LittleEndian.PutUint32(potentialXValue, 2) 55 | for i, elem := range s256.Sum(nil) { 56 | potentialXValue[i+1] = elem 57 | } 58 | 59 | gen2, err := ParsePubKey(potentialXValue, S256()) 60 | if err != nil { 61 | log.Fatalf("Could not create H %v\n", err) 62 | } 63 | 64 | doublingPoints := make([][3]fieldVal, curve.BitSize) 65 | 66 | // initialize px, py, pz to the Jacobian coordinates for the base point 67 | px, py := curve.bigAffineToField(gen2.X, gen2.Y) 68 | pz := new(fieldVal).SetInt(1) 69 | for i := 0; i < curve.BitSize; i++ { 70 | doublingPoints[i] = [3]fieldVal{*px, *py, *pz} 71 | // P = 2*P 72 | curve.doubleJacobian(px, py, pz, px, py, pz) 73 | } 74 | return doublingPoints 75 | } 76 | 77 | // SerializedBytePoints returns a serialized byte slice which contains all of 78 | // the possible points per 8-bit window. This is used to when generating 79 | // secp256k1.go. 80 | func (curve *KoblitzCurve) SerializedBytePoints() []byte { 81 | doublingPoints := curve.getDoublingPoints() 82 | 83 | // Segregate the bits into byte-sized windows 84 | serialized := make([]byte, curve.byteSize*256*3*10*4) 85 | offset := 0 86 | for byteNum := 0; byteNum < curve.byteSize; byteNum++ { 87 | // Grab the 8 bits that make up this byte from doublingPoints. 88 | startingBit := 8 * (curve.byteSize - byteNum - 1) 89 | computingPoints := doublingPoints[startingBit : startingBit+8] 90 | 91 | // Compute all points in this window and serialize them. 92 | for i := 0; i < 256; i++ { 93 | px, py, pz := new(fieldVal), new(fieldVal), new(fieldVal) 94 | for j := 0; j < 8; j++ { 95 | if i>>uint(j)&1 == 1 { 96 | curve.addJacobian(px, py, pz, &computingPoints[j][0], 97 | &computingPoints[j][1], &computingPoints[j][2], px, py, pz) 98 | } 99 | } 100 | for i := 0; i < 10; i++ { 101 | binary.LittleEndian.PutUint32(serialized[offset:], px.n[i]) 102 | offset += 4 103 | } 104 | for i := 0; i < 10; i++ { 105 | binary.LittleEndian.PutUint32(serialized[offset:], py.n[i]) 106 | offset += 4 107 | } 108 | for i := 0; i < 10; i++ { 109 | binary.LittleEndian.PutUint32(serialized[offset:], pz.n[i]) 110 | offset += 4 111 | } 112 | } 113 | } 114 | 115 | return serialized 116 | } 117 | 118 | // SerializedBytePointsH returns a serialized byte slice which contains all of 119 | // the possible points per 8-bit window for H. This is used to when generating 120 | // secp256k1H.go. <-- note the H 121 | func (curve *KoblitzCurve) SerializedBytePointsH() []byte { 122 | doublingPoints := curve.getDoublingPointsH() 123 | 124 | // Segregate the bits into byte-sized windows 125 | serialized := make([]byte, curve.byteSize*256*3*10*4) 126 | offset := 0 127 | for byteNum := 0; byteNum < curve.byteSize; byteNum++ { 128 | // Grab the 8 bits that make up this byte from doublingPoints. 129 | startingBit := 8 * (curve.byteSize - byteNum - 1) 130 | computingPoints := doublingPoints[startingBit : startingBit+8] 131 | 132 | // Compute all points in this window and serialize them. 133 | for i := 0; i < 256; i++ { 134 | px, py, pz := new(fieldVal), new(fieldVal), new(fieldVal) 135 | for j := 0; j < 8; j++ { 136 | if i>>uint(j)&1 == 1 { 137 | curve.addJacobian(px, py, pz, &computingPoints[j][0], 138 | &computingPoints[j][1], &computingPoints[j][2], px, py, pz) 139 | } 140 | } 141 | for i := 0; i < 10; i++ { 142 | binary.LittleEndian.PutUint32(serialized[offset:], px.n[i]) 143 | offset += 4 144 | } 145 | for i := 0; i < 10; i++ { 146 | binary.LittleEndian.PutUint32(serialized[offset:], py.n[i]) 147 | offset += 4 148 | } 149 | for i := 0; i < 10; i++ { 150 | binary.LittleEndian.PutUint32(serialized[offset:], pz.n[i]) 151 | offset += 4 152 | } 153 | } 154 | } 155 | 156 | return serialized 157 | } 158 | 159 | // sqrt returns the square root of the provided big integer using Newton's 160 | // method. It's only compiled and used during generation of pre-computed 161 | // values, so speed is not a huge concern. 162 | func sqrt(n *big.Int) *big.Int { 163 | // Initial guess = 2^(log_2(n)/2) 164 | guess := big.NewInt(2) 165 | guess.Exp(guess, big.NewInt(int64(n.BitLen()/2)), nil) 166 | 167 | // Now refine using Newton's method. 168 | big2 := big.NewInt(2) 169 | prevGuess := big.NewInt(0) 170 | for { 171 | prevGuess.Set(guess) 172 | guess.Add(guess, new(big.Int).Div(n, guess)) 173 | guess.Div(guess, big2) 174 | if guess.Cmp(prevGuess) == 0 { 175 | break 176 | } 177 | } 178 | return guess 179 | } 180 | 181 | // EndomorphismVectors runs the first 3 steps of algorithm 3.74 from [GECC] to 182 | // generate the linearly independent vectors needed to generate a balanced 183 | // length-two representation of a multiplier such that k = k1 + k2λ (mod N) and 184 | // returns them. Since the values will always be the same given the fact that N 185 | // and λ are fixed, the final results can be accelerated by storing the 186 | // precomputed values with the curve. 187 | func (curve *KoblitzCurve) EndomorphismVectors() (a1, b1, a2, b2 *big.Int) { 188 | bigMinus1 := big.NewInt(-1) 189 | 190 | // This section uses an extended Euclidean algorithm to generate a 191 | // sequence of equations: 192 | // s[i] * N + t[i] * λ = r[i] 193 | 194 | nSqrt := sqrt(curve.N) 195 | u, v := new(big.Int).Set(curve.N), new(big.Int).Set(curve.lambda) 196 | x1, y1 := big.NewInt(1), big.NewInt(0) 197 | x2, y2 := big.NewInt(0), big.NewInt(1) 198 | q, r := new(big.Int), new(big.Int) 199 | qu, qx1, qy1 := new(big.Int), new(big.Int), new(big.Int) 200 | s, t := new(big.Int), new(big.Int) 201 | ri, ti := new(big.Int), new(big.Int) 202 | a1, b1, a2, b2 = new(big.Int), new(big.Int), new(big.Int), new(big.Int) 203 | found, oneMore := false, false 204 | for u.Sign() != 0 { 205 | // q = v/u 206 | q.Div(v, u) 207 | 208 | // r = v - q*u 209 | qu.Mul(q, u) 210 | r.Sub(v, qu) 211 | 212 | // s = x2 - q*x1 213 | qx1.Mul(q, x1) 214 | s.Sub(x2, qx1) 215 | 216 | // t = y2 - q*y1 217 | qy1.Mul(q, y1) 218 | t.Sub(y2, qy1) 219 | 220 | // v = u, u = r, x2 = x1, x1 = s, y2 = y1, y1 = t 221 | v.Set(u) 222 | u.Set(r) 223 | x2.Set(x1) 224 | x1.Set(s) 225 | y2.Set(y1) 226 | y1.Set(t) 227 | 228 | // As soon as the remainder is less than the sqrt of n, the 229 | // values of a1 and b1 are known. 230 | if !found && r.Cmp(nSqrt) < 0 { 231 | // When this condition executes ri and ti represent the 232 | // r[i] and t[i] values such that i is the greatest 233 | // index for which r >= sqrt(n). Meanwhile, the current 234 | // r and t values are r[i+1] and t[i+1], respectively. 235 | 236 | // a1 = r[i+1], b1 = -t[i+1] 237 | a1.Set(r) 238 | b1.Mul(t, bigMinus1) 239 | found = true 240 | oneMore = true 241 | 242 | // Skip to the next iteration so ri and ti are not 243 | // modified. 244 | continue 245 | 246 | } else if oneMore { 247 | // When this condition executes ri and ti still 248 | // represent the r[i] and t[i] values while the current 249 | // r and t are r[i+2] and t[i+2], respectively. 250 | 251 | // sum1 = r[i]^2 + t[i]^2 252 | rSquared := new(big.Int).Mul(ri, ri) 253 | tSquared := new(big.Int).Mul(ti, ti) 254 | sum1 := new(big.Int).Add(rSquared, tSquared) 255 | 256 | // sum2 = r[i+2]^2 + t[i+2]^2 257 | r2Squared := new(big.Int).Mul(r, r) 258 | t2Squared := new(big.Int).Mul(t, t) 259 | sum2 := new(big.Int).Add(r2Squared, t2Squared) 260 | 261 | // if (r[i]^2 + t[i]^2) <= (r[i+2]^2 + t[i+2]^2) 262 | if sum1.Cmp(sum2) <= 0 { 263 | // a2 = r[i], b2 = -t[i] 264 | a2.Set(ri) 265 | b2.Mul(ti, bigMinus1) 266 | } else { 267 | // a2 = r[i+2], b2 = -t[i+2] 268 | a2.Set(r) 269 | b2.Mul(t, bigMinus1) 270 | } 271 | 272 | // All done. 273 | break 274 | } 275 | 276 | ri.Set(r) 277 | ti.Set(t) 278 | } 279 | 280 | return a1, b1, a2, b2 281 | } 282 | -------------------------------------------------------------------------------- /abc.go: -------------------------------------------------------------------------------- 1 | package zksigma 2 | 3 | import ( 4 | "bytes" 5 | "crypto/rand" 6 | "math/big" 7 | 8 | "github.com/mit-dci/zksigma/wire" 9 | ) 10 | 11 | // ABCProof is a proof that generates a proof that the relationship between three 12 | // scalars a, b and c is ab = c 13 | // 14 | // MAPPING[a, b, c] :: [v, inv(v), c] 15 | // 16 | // Public: G, H, CM, B, C, CMTok where 17 | // - CM = vG + uaH // we do not know ua, only v 18 | // - B = inv(v)G + ubH //inv is multiplicative inverse, in the case of v = 0, inv(v) = 0 19 | // - C = (v * inv(v))G + ucH // c = v * inv(v) 20 | // - CMTok = uaPK = ua(skH) // ua is r from CM 21 | // 22 | // Prover Verifier 23 | // ====== ====== 24 | // generate in order: 25 | // - commitment of inv(v), B 26 | // - commitment of v * inv(v), C // either 0 or 1 ONLY 27 | // - Disjunctive proof of v = 0 or c = 1 28 | // select u1, u2, u3 at random 29 | // select ub, uc at random // ua was before proof 30 | // Compute: 31 | // - T1 = u1G + u2CMTok 32 | // - T2 = u1B + u3H 33 | // - chal = HASH(G,H,CM,CMTok,B,C,T1,T2) 34 | // Compute: 35 | // - j = u1 + v * chal 36 | // - k = u2 + inv(sk) * chal 37 | // - l = u3 + (uc - v * ub) * chal 38 | // 39 | // disjuncAC, B, C, T1, T2, c, j, k, l -------> 40 | // disjuncAC ?= true 41 | // chal ?= HASH(G,H,CM,CMTok,B,C,T1,T2) 42 | // chal*CM + T1 ?= jG + kCMTok 43 | // chal*C + T2 ?= jB + lH˜ 44 | type ABCProof struct { 45 | B ECPoint // commitment for b = 0 OR inv(v) 46 | C ECPoint // commitment for c = 0 OR 1 ONLY 47 | T1 ECPoint // T1 = u1G + u2MTok 48 | T2 ECPoint // T2 = u1B + u3H 49 | Challenge *big.Int // chal = HASH(G,H,CM,CMTok,B,C,T1,T2) 50 | j *big.Int // j = u1 + v * chal 51 | k *big.Int // k = u2 + inv(sk) * chal 52 | l *big.Int // l = u3 + (uc - v * ub) * chal 53 | CToken ECPoint 54 | disjuncAC *DisjunctiveProof 55 | } 56 | 57 | // NewABCProof generates a proof that the relationship between three scalars a,b and c is ab = c, 58 | // in commitments A, B and C respectively. 59 | // Option Left is proving that A and C commit to zero and simulates that A, B and C commit to v, inv(v) and 1 respectively. 60 | // Option Right is proving that A, B and C commit to v, inv(v) and 1 respectively and simulating that A and C commit to 0. 61 | func NewABCProof(zkpcp ZKPCurveParams, CM, CMTok ECPoint, value, sk *big.Int, option Side) (*ABCProof, error) { 62 | 63 | // We cannot check that CM log is actually the value, but the verification should catch that 64 | 65 | u1, err := rand.Int(rand.Reader, zkpcp.C.Params().N) 66 | if err != nil { 67 | return nil, err 68 | } 69 | u2, err := rand.Int(rand.Reader, zkpcp.C.Params().N) 70 | if err != nil { 71 | return nil, err 72 | } 73 | 74 | u3, err := rand.Int(rand.Reader, zkpcp.C.Params().N) 75 | if err != nil { 76 | return nil, err 77 | } 78 | 79 | ub, err := rand.Int(rand.Reader, zkpcp.C.Params().N) 80 | if err != nil { 81 | return nil, err 82 | } 83 | uc, err := rand.Int(rand.Reader, zkpcp.C.Params().N) 84 | if err != nil { 85 | return nil, err 86 | } 87 | 88 | B := ECPoint{} 89 | C := ECPoint{} 90 | CToken := zkpcp.Mult(zkpcp.Mult(zkpcp.H, sk), uc) 91 | 92 | var disjuncAC *DisjunctiveProof 93 | var e error 94 | // Disjunctive Proof of a = 0 or c = 1 95 | if option == Left && value.Cmp(BigZero) == 0 { 96 | // MUST: a = 0! ; side = left 97 | // No inverse if value=0; set B to 0. Do we confirm somewhere else that a=0? 98 | B = PedCommitR(zkpcp, big.NewInt(0), ub) 99 | 100 | // C = 0 + ucH 101 | C = PedCommitR(zkpcp, big.NewInt(0), uc) 102 | 103 | // CM is considered the "base" of CMTok since it would be only uaH and not ua sk H 104 | // C - G is done regardless of the c = 0 or 1 because in the case c = 0 it does matter what that random number is 105 | disjuncAC, e = NewDisjunctiveProof(zkpcp, CM, CMTok, zkpcp.H, zkpcp.Sub(C, zkpcp.G), sk, Left) 106 | } else if option == Right && value.Cmp(BigZero) != 0 { 107 | // MUST: c = 1! ; side = right 108 | 109 | B = PedCommitR(zkpcp, new(big.Int).ModInverse(value, zkpcp.C.Params().N), ub) 110 | 111 | // C = G + ucH 112 | C = PedCommitR(zkpcp, big.NewInt(1), uc) 113 | 114 | // Look at notes a couple lines above on what the input is like this 115 | disjuncAC, e = NewDisjunctiveProof(zkpcp, CM, CMTok, zkpcp.H, zkpcp.Sub(C, zkpcp.G), uc, Right) 116 | } else { 117 | return &ABCProof{}, &errorProof{"ABCProof", "invalid side-value pair passed"} 118 | } 119 | 120 | if e != nil { 121 | return &ABCProof{}, &errorProof{"ABCProof", "disjunctiveProve within ABCProve failed to generate"} 122 | } 123 | 124 | // CMTok is Ta for the rest of the proof 125 | // T1 = u1G + u2Ta 126 | // u1G 127 | u1G := zkpcp.Mult(zkpcp.G, u1) 128 | // u2Ta 129 | u2Ta := zkpcp.Mult(CMTok, u2) 130 | // Sum the above two 131 | T1 := zkpcp.Add(u1G, u2Ta) 132 | 133 | // T2 = u1B + u3H 134 | // u1B 135 | u1B := zkpcp.Mult(B, u1) 136 | // u3H 137 | u3H := zkpcp.Mult(zkpcp.H, u3) 138 | // Sum of the above two 139 | T2 := zkpcp.Add(u1B, u3H) 140 | 141 | // chal = HASH(G,H,CM,CMTok,B,C,T1,T2) 142 | Challenge := GenerateChallenge(zkpcp, zkpcp.G.Bytes(), zkpcp.H.Bytes(), 143 | CM.Bytes(), CMTok.Bytes(), 144 | B.Bytes(), C.Bytes(), 145 | T1.Bytes(), T2.Bytes()) 146 | 147 | // j = u1 + v * chal 148 | j := new(big.Int).Add(u1, new(big.Int).Mul(value, Challenge)) 149 | j = new(big.Int).Mod(j, zkpcp.C.Params().N) 150 | 151 | // k = u2 + inv(sk) * chal 152 | // inv(sk) 153 | isk := new(big.Int).ModInverse(sk, zkpcp.C.Params().N) 154 | k := new(big.Int).Add(u2, new(big.Int).Mul(isk, Challenge)) 155 | k = new(big.Int).Mod(k, zkpcp.C.Params().N) 156 | 157 | // l = u3 + (uc - v * ub) * chal 158 | temp1 := new(big.Int).Sub(uc, new(big.Int).Mul(value, ub)) 159 | l := new(big.Int).Add(u3, new(big.Int).Mul(temp1, Challenge)) 160 | 161 | return &ABCProof{ 162 | B, 163 | C, 164 | T1, 165 | T2, 166 | Challenge, 167 | j, k, l, CToken, 168 | disjuncAC}, nil 169 | 170 | } 171 | 172 | // Verify checks if ABCProof aProof with appropriate commits CM and CMTok is correct 173 | func (aProof *ABCProof) Verify(zkpcp ZKPCurveParams, CM, CMTok ECPoint) (bool, error) { 174 | 175 | // Notes in ABCProof talk about why the Disjunc takes in this specific input even though it looks non-intuitive 176 | // Here it is important that you subtract exactly 1 G from the aProof.C because that only allows for you to prove c = 1! 177 | _, status := aProof.disjuncAC.Verify(zkpcp, CM, CMTok, zkpcp.H, zkpcp.Sub(aProof.C, zkpcp.G)) 178 | 179 | if status != nil { 180 | return false, &errorProof{"ABCVerify", "ABCProof for disjuncAC is false or not generated properly"} 181 | } 182 | 183 | Challenge := GenerateChallenge(zkpcp, zkpcp.G.Bytes(), zkpcp.H.Bytes(), 184 | CM.Bytes(), CMTok.Bytes(), 185 | aProof.B.Bytes(), aProof.C.Bytes(), 186 | aProof.T1.Bytes(), aProof.T2.Bytes()) 187 | 188 | // chal = HASH(G,H,CM,CMTok,B,C,T1,T2) 189 | if Challenge.Cmp(aProof.Challenge) != 0 { 190 | return false, &errorProof{"ABCVerify", "proof contains incorrect challenge"} 191 | } 192 | 193 | // chalCM + T1 ?= jG + kCMTok 194 | // chalCM 195 | chalA := zkpcp.Mult(CM, Challenge) 196 | // + T1 197 | lhs1 := zkpcp.Add(chalA, aProof.T1) 198 | //jG 199 | jG := zkpcp.Mult(zkpcp.G, aProof.j) 200 | // kCMTok 201 | kCMTok := zkpcp.Mult(CMTok, aProof.k) 202 | // jG + kCMTok 203 | rhs1 := zkpcp.Add(jG, kCMTok) 204 | 205 | if !lhs1.Equal(rhs1) { 206 | return false, &errorProof{"ABCProof", "cCM + T1 != jG + kCMTok"} 207 | } 208 | 209 | // cC + T2 ?= jB + lH 210 | chalC := zkpcp.Mult(aProof.C, Challenge) 211 | lhs2 := zkpcp.Add(chalC, aProof.T2) 212 | 213 | jB := zkpcp.Mult(aProof.B, aProof.j) 214 | lH := zkpcp.Mult(zkpcp.H, aProof.l) 215 | rhs2 := zkpcp.Add(jB, lH) 216 | 217 | if !lhs2.Equal(rhs2) { 218 | return false, &errorProof{"ABCVerify", "cC + T2 != jB + lH"} 219 | } 220 | 221 | return true, nil 222 | } 223 | 224 | // Bytes returns a byte slice with a serialized representation of ABCProof proof 225 | func (proof *ABCProof) Bytes() []byte { 226 | var buf bytes.Buffer 227 | 228 | WriteECPoint(&buf, proof.B) 229 | WriteECPoint(&buf, proof.C) 230 | WriteECPoint(&buf, proof.T1) 231 | WriteECPoint(&buf, proof.T2) 232 | WriteBigInt(&buf, proof.Challenge) 233 | WriteBigInt(&buf, proof.j) 234 | WriteBigInt(&buf, proof.k) 235 | WriteBigInt(&buf, proof.l) 236 | WriteECPoint(&buf, proof.CToken) 237 | wire.WriteVarBytes(&buf, proof.disjuncAC.Bytes()) 238 | 239 | return buf.Bytes() 240 | } 241 | 242 | // NewABCProofFromBytes returns an ABCProof generated from the deserialization of 243 | // byte slice b 244 | func NewABCProofFromBytes(b []byte) (*ABCProof, error) { 245 | proof := new(ABCProof) 246 | buf := bytes.NewBuffer(b) 247 | var err error 248 | proof.B, err = ReadECPoint(buf) 249 | if err != nil { 250 | return nil, err 251 | } 252 | proof.C, err = ReadECPoint(buf) 253 | if err != nil { 254 | return nil, err 255 | } 256 | proof.T1, err = ReadECPoint(buf) 257 | if err != nil { 258 | return nil, err 259 | } 260 | proof.T2, err = ReadECPoint(buf) 261 | if err != nil { 262 | return nil, err 263 | } 264 | proof.Challenge, err = ReadBigInt(buf) 265 | if err != nil { 266 | return nil, err 267 | } 268 | proof.j, err = ReadBigInt(buf) 269 | if err != nil { 270 | return nil, err 271 | } 272 | proof.k, err = ReadBigInt(buf) 273 | if err != nil { 274 | return nil, err 275 | } 276 | proof.l, err = ReadBigInt(buf) 277 | if err != nil { 278 | return nil, err 279 | } 280 | proof.CToken, err = ReadECPoint(buf) 281 | if err != nil { 282 | return nil, err 283 | } 284 | disjuncBytes, err := wire.ReadVarBytes(buf, 100000, "disjunctProof") 285 | if err != nil { 286 | return nil, err 287 | } 288 | proof.disjuncAC, err = NewDisjunctiveProofFromBytes(disjuncBytes) 289 | if err != nil { 290 | return nil, err 291 | } 292 | return proof, nil 293 | } 294 | -------------------------------------------------------------------------------- /crypto_test.go: -------------------------------------------------------------------------------- 1 | package zksigma 2 | 3 | import ( 4 | "crypto/rand" 5 | "math/big" 6 | "testing" 7 | ) 8 | 9 | func TestECPointMethods(t *testing.T) { 10 | v := big.NewInt(3) 11 | p := TestCurve.Mult(TestCurve.G, v) 12 | negp := TestCurve.Neg(p) 13 | sum := TestCurve.Add(p, negp) 14 | if !sum.Equal(Zero) { 15 | t.Logf("p : %v\n", p) 16 | t.Logf("negp : %v\n", negp) 17 | t.Logf("sum : %v\n", sum) 18 | t.Fatalf("p + -p should be 0\n") 19 | } 20 | negnegp := TestCurve.Neg(negp) 21 | if !negnegp.Equal(p) { 22 | t.Logf("p : %v\n", p) 23 | t.Logf("negnegp : %v\n", negnegp) 24 | t.Fatalf("-(-p) should be p\n") 25 | } 26 | sum = TestCurve.Add(p, Zero) 27 | if !sum.Equal(p) { 28 | t.Logf("p : %v\n", p) 29 | t.Logf("sum : %v\n", sum) 30 | t.Fatalf("p + 0 should be p\n") 31 | } 32 | } 33 | 34 | func TestZkpCryptoStuff(t *testing.T) { 35 | value := big.NewInt(-100) 36 | 37 | testCommit, randomValue, err := PedCommit(TestCurve, value) // CM = xG + rH 38 | 39 | if err != nil { 40 | t.Fatalf("%v\n", err) 41 | } 42 | 43 | value = new(big.Int).Mod(value, TestCurve.C.Params().N) // v % p 44 | 45 | ValEC := TestCurve.Mult(TestCurve.G, value) // vG 46 | InvValEC := TestCurve.Neg(ValEC) // 1/vG (actually mod operation but whatever you get it) 47 | 48 | t.Logf(" vG : %v --- value : %v \n", ValEC, value) 49 | t.Logf("1/vG : %v\n", InvValEC) 50 | 51 | temp := TestCurve.Add(ValEC, InvValEC) 52 | t.Logf("TestZkpCrypto:") 53 | t.Logf("Added the above: %v\n", temp) 54 | 55 | if !temp.Equal(Zero) { 56 | t.Logf("Added the above: %v", temp) 57 | t.Logf("The above should have been (0,0)") 58 | t.Fatalf("Failed Addition of inverse points failed") 59 | } 60 | 61 | testOpen := TestCurve.Add(InvValEC, testCommit) // 1/vG + vG + rH ?= rH (1/vG + vG = 0, hopefully) 62 | RandEC := TestCurve.Mult(TestCurve.H, randomValue) // rH 63 | 64 | if !RandEC.Equal(testOpen) { 65 | t.Logf("RandEC : %v\n", RandEC) 66 | t.Logf("testOpen : %v\n", testOpen) 67 | t.Fatalf("RandEC should have been equal to testOpen\n") 68 | } 69 | } 70 | 71 | func TestZkpCryptoCommitR(t *testing.T) { 72 | 73 | u, err := rand.Int(rand.Reader, TestCurve.C.Params().N) 74 | if err != nil { 75 | t.Fatalf("%v\n", err) 76 | } 77 | 78 | testCommit := CommitR(TestCurve, TestCurve.H, u) 79 | 80 | if !(VerifyR(TestCurve, testCommit, TestCurve.H, u)) { 81 | t.Logf("testCommit: %v\n", testCommit) 82 | t.Logf("TestCurve.H: %v, \n", TestCurve.H) 83 | t.Logf("u : %v\n", u) 84 | t.Fatalf("testCommit should have passed verification\n") 85 | } 86 | } 87 | 88 | func TestPedersenCommit(t *testing.T) { 89 | 90 | x := big.NewInt(1000) 91 | badx := big.NewInt(1234) 92 | 93 | commit, u, err := PedCommit(TestCurve, x) 94 | if err != nil { 95 | t.Fatalf("%v\n", err) 96 | } 97 | 98 | commitR := PedCommitR(TestCurve, x, u) 99 | 100 | if !commit.Equal(commitR) { 101 | t.Logf("x : %v --- u : %v\n", x, u) 102 | t.Logf("commit: %v\n", commit) 103 | t.Logf("commitR: %v\n", commitR) 104 | t.Fatalf("commit and commitR should be equal") 105 | } 106 | 107 | if !Open(TestCurve, x, u, commit) || !Open(TestCurve, x, u, commitR) { 108 | t.Logf("x : %v --- u : %v\n", x, u) 109 | t.Logf("commit: %v\n", commit) 110 | t.Logf("commitR: %v\n", commitR) 111 | t.Fatalf("commit and/or commitR did not successfully open") 112 | } 113 | 114 | if Open(TestCurve, badx, u.Neg(u), commit) || Open(TestCurve, badx, u.Neg(u), commitR) { 115 | t.Logf("x : %v --- u : %v\n", x, u) 116 | t.Logf("commit: %v\n", commit) 117 | t.Logf("commitR: %v\n", commitR) 118 | t.Fatalf("commit and/or commitR should not have opened properly") 119 | } 120 | 121 | } 122 | 123 | // TODO: make a ton more test cases 124 | 125 | type etx struct { 126 | CM ECPoint 127 | CMTok ECPoint 128 | ABCP *ABCProof 129 | } 130 | 131 | //TODO: make a sk-pk that is consistant across all test cases 132 | func TestAverages_Basic(t *testing.T) { 133 | 134 | // remember to change both number here... 135 | numTx := 100 136 | numTranx := big.NewInt(100) 137 | 138 | totalValue := big.NewInt(0) 139 | totalRand := big.NewInt(0) 140 | txn := make([]etx, numTx) 141 | sk, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 142 | PK := TestCurve.Mult(TestCurve.H, sk) 143 | var value *big.Int 144 | var commRand *big.Int 145 | var err error 146 | 147 | // Generate 148 | for ii := 0; ii < numTx; ii++ { 149 | value, _ = rand.Int(rand.Reader, TestCurve.C.Params().N) 150 | totalValue.Add(totalValue, value) 151 | txn[ii].CM, commRand, err = PedCommit(TestCurve, value) 152 | if err != nil { 153 | t.Fatalf("%v\n", err) 154 | } 155 | totalRand.Add(totalRand, commRand) 156 | txn[ii].CMTok = TestCurve.Mult(PK, commRand) 157 | txn[ii].ABCP, _ = NewABCProof(TestCurve, txn[ii].CM, txn[ii].CMTok, value, sk, Right) 158 | } 159 | 160 | // Purely for testing purposes, usually this is computed at the end by auditor 161 | // actualAverage := new(big.Int).Quo(totalValue, numTranx) 162 | 163 | // ========= BANK PROCESS =========== 164 | 165 | // To calculate average we need to first show proof of knowledge 166 | // of the sums of both the total value of transactions and the 167 | // sum of the C-bit commitments 168 | // This process is exactly the same process described in zkLedger 169 | // (Neha Nerula) paper in section 4.2 170 | 171 | //Need to aggregate a bunch of stuff to do equivalence proofs and what not 172 | totalCM := Zero 173 | totalCMTok := Zero 174 | totalC := Zero 175 | totalCTok := Zero 176 | 177 | for ii := 0; ii < numTx; ii++ { 178 | totalCM = TestCurve.Add(txn[ii].CM, totalCM) 179 | totalCMTok = TestCurve.Add(txn[ii].CMTok, totalCMTok) 180 | totalC = TestCurve.Add(txn[ii].ABCP.C, totalC) 181 | totalCTok = TestCurve.Add(txn[ii].ABCP.CToken, totalCTok) 182 | } 183 | 184 | // makes the call look cleaner 185 | B1 := TestCurve.Add(totalC, TestCurve.Neg(TestCurve.Mult(TestCurve.G, numTranx))) 186 | R1 := totalCTok 187 | B2 := TestCurve.H 188 | R2 := PK 189 | 190 | eProofNumTx, status := NewEquivalenceProof(TestCurve, B1, R1, B2, R2, sk) 191 | 192 | if status != nil { 193 | proofStatus(status.(*errorProof)) 194 | t.Logf("Average Test: equivalence proof failed to generate for numTx\n") 195 | t.Fatalf("Averages did not generate correct NUMTX equivalence proof\n") 196 | } 197 | 198 | B1 = TestCurve.Add(totalCM, TestCurve.Neg(TestCurve.Mult(TestCurve.G, totalValue))) 199 | R1 = totalCMTok 200 | 201 | eProofValue, status1 := NewEquivalenceProof(TestCurve, B1, R1, B2, R2, sk) 202 | 203 | if status1 != nil { 204 | proofStatus(status1.(*errorProof)) 205 | t.Logf("Average Test: equivalence proof failed to generate for value sum\n") 206 | t.Fatalf("Averages did not generate correct VALUE equivalence proof\n") 207 | } 208 | 209 | // ASSUME: 210 | // eProofs passed to auditor 211 | // clear text answers of total value and total number tx passed to auditor 212 | // auditor WILL recalculate all the totals (totalCM, totalCMTok, etc) before doing the following 213 | // auditor WILL recalculate the B1's as shown above 214 | // auditor WILL verify eProofs and then perform the final average calculation, shown below 215 | // ======== AUDITOR PROCESS =========== 216 | 217 | B1 = TestCurve.Add(totalC, TestCurve.Neg(TestCurve.Mult(TestCurve.G, numTranx))) 218 | R1 = totalCTok 219 | B2 = TestCurve.H 220 | R2 = PK 221 | 222 | checkTx, err := eProofNumTx.Verify(TestCurve, B1, R1, B2, R2) 223 | 224 | if err != nil { 225 | t.Fatalf("Error while calling equivalence proof verify: %s", err.Error()) 226 | } 227 | 228 | if !checkTx { 229 | t.Logf("Average Test: NUMTX equivalence proof did not verify\n") 230 | t.Fatalf("equivalence proof of NUMTX did not verify\n") 231 | } 232 | 233 | B1 = TestCurve.Add(totalCM, TestCurve.Neg(TestCurve.Mult(TestCurve.G, totalValue))) 234 | R1 = totalCMTok 235 | 236 | checkVal, err := eProofValue.Verify(TestCurve, B1, R1, B2, R2) 237 | 238 | if err != nil { 239 | t.Fatalf("Error while calling equivalence proof verify: %s", err.Error()) 240 | } 241 | 242 | if !checkVal { 243 | t.Logf("Average Test: SUM equivalence proof did not verify\n") 244 | t.Fatalf("Equivalence proof of SUM did not verify\n") 245 | } 246 | 247 | } 248 | 249 | // func TestBigZeroAssignment(t *testing.T) { 250 | // TestBigZero := big.NewInt(0) 251 | 252 | // assign1 := TestBigZero // assign will be using TestBigZero pointer from here on 253 | // assign1.Add(assign1, big.NewInt(1)) // TestBigZero looks like it does not change but actually does 254 | 255 | // assign2 := TestBigZero // assign2 = TestBigZero = 1 256 | 257 | // if assign1.Cmp(assign2) == 0 { 258 | // t.Fatalf("THIS TEST WILL FAIL FOR DEMO PURPOSES: should not be equal %v", TestBigZero) 259 | // } 260 | 261 | // } 262 | 263 | // func TestZeroAssignment(t *testing.T) { 264 | // TestBigZero := Zero 265 | // One := TestCurve.G 266 | 267 | // cool := TestBigZero.Add(One) // TestBigZero does not actually change 268 | 269 | // assign2 := TestBigZero // assign2 = TestBigZero = 1 270 | 271 | // if cool.Equal(assign2) { 272 | // t.Fatalf("THIS TEST WILL FAIL FOR DEMO PURPOSES: should not be equal %v", TestBigZero) 273 | // } 274 | 275 | // } 276 | 277 | // ============== BENCHMARKS ================= 278 | func BenchmarkPedCommit(b *testing.B) { 279 | value, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 280 | b.ResetTimer() 281 | for ii := 0; ii < b.N; ii++ { 282 | PedCommit(TestCurve, value) 283 | } 284 | } 285 | 286 | func BenchmarkPedCommitR(b *testing.B) { 287 | value, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 288 | randVal, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 289 | b.ResetTimer() 290 | for ii := 0; ii < b.N; ii++ { 291 | PedCommitR(TestCurve, value, randVal) 292 | } 293 | } 294 | 295 | func BenchmarkOpen(b *testing.B) { 296 | value, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 297 | randVal, _ := rand.Int(rand.Reader, TestCurve.C.Params().N) 298 | CM := PedCommitR(TestCurve, value, randVal) 299 | b.ResetTimer() 300 | for ii := 0; ii < b.N; ii++ { 301 | Open(TestCurve, value, randVal, CM) 302 | } 303 | } 304 | -------------------------------------------------------------------------------- /wire/common.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013-2016 The btcsuite developers 2 | // Use of this source code is governed by an ISC 3 | // license that can be found in the LICENSE file. 4 | 5 | package wire 6 | 7 | import ( 8 | "crypto/rand" 9 | "encoding/binary" 10 | "fmt" 11 | "io" 12 | "math" 13 | ) 14 | 15 | const ( 16 | // MaxVarIntPayload is the maximum payload size for a variable length integer. 17 | MaxVarIntPayload = 9 18 | 19 | // binaryFreeListMaxItems is the number of buffers to keep in the free 20 | // list to use for binary serialization and deserialization. 21 | binaryFreeListMaxItems = 1024 22 | ) 23 | 24 | var ( 25 | // littleEndian is a convenience variable since binary.LittleEndian is 26 | // quite long. 27 | littleEndian = binary.LittleEndian 28 | 29 | // bigEndian is a convenience variable since binary.BigEndian is quite 30 | // long. 31 | bigEndian = binary.BigEndian 32 | ) 33 | 34 | // binaryFreeList defines a concurrent safe free list of byte slices (up to the 35 | // maximum number defined by the binaryFreeListMaxItems constant) that have a 36 | // cap of 8 (thus it supports up to a uint64). It is used to provide temporary 37 | // buffers for serializing and deserializing primitive numbers to and from their 38 | // binary encoding in order to greatly reduce the number of allocations 39 | // required. 40 | // 41 | // For convenience, functions are provided for each of the primitive unsigned 42 | // integers that automatically obtain a buffer from the free list, perform the 43 | // necessary binary conversion, read from or write to the given io.Reader or 44 | // io.Writer, and return the buffer to the free list. 45 | type binaryFreeList chan []byte 46 | 47 | // Borrow returns a byte slice from the free list with a length of 8. A new 48 | // buffer is allocated if there are not any available on the free list. 49 | func (l binaryFreeList) Borrow() []byte { 50 | var buf []byte 51 | select { 52 | case buf = <-l: 53 | default: 54 | buf = make([]byte, 8) 55 | } 56 | return buf[:8] 57 | } 58 | 59 | // Return puts the provided byte slice back on the free list. The buffer MUST 60 | // have been obtained via the Borrow function and therefore have a cap of 8. 61 | func (l binaryFreeList) Return(buf []byte) { 62 | select { 63 | case l <- buf: 64 | default: 65 | // Let it go to the garbage collector. 66 | } 67 | } 68 | 69 | // Uint8 reads a single byte from the provided reader using a buffer from the 70 | // free list and returns it as a uint8. 71 | func (l binaryFreeList) Uint8(r io.Reader) (uint8, error) { 72 | buf := l.Borrow()[:1] 73 | if _, err := io.ReadFull(r, buf); err != nil { 74 | l.Return(buf) 75 | return 0, err 76 | } 77 | rv := buf[0] 78 | l.Return(buf) 79 | return rv, nil 80 | } 81 | 82 | // Uint16 reads two bytes from the provided reader using a buffer from the 83 | // free list, converts it to a number using the provided byte order, and returns 84 | // the resulting uint16. 85 | func (l binaryFreeList) Uint16(r io.Reader, byteOrder binary.ByteOrder) (uint16, error) { 86 | buf := l.Borrow()[:2] 87 | if _, err := io.ReadFull(r, buf); err != nil { 88 | l.Return(buf) 89 | return 0, err 90 | } 91 | rv := byteOrder.Uint16(buf) 92 | l.Return(buf) 93 | return rv, nil 94 | } 95 | 96 | // Uint32 reads four bytes from the provided reader using a buffer from the 97 | // free list, converts it to a number using the provided byte order, and returns 98 | // the resulting uint32. 99 | func (l binaryFreeList) Uint32(r io.Reader, byteOrder binary.ByteOrder) (uint32, error) { 100 | buf := l.Borrow()[:4] 101 | if _, err := io.ReadFull(r, buf); err != nil { 102 | l.Return(buf) 103 | return 0, err 104 | } 105 | rv := byteOrder.Uint32(buf) 106 | l.Return(buf) 107 | return rv, nil 108 | } 109 | 110 | // Uint64 reads eight bytes from the provided reader using a buffer from the 111 | // free list, converts it to a number using the provided byte order, and returns 112 | // the resulting uint64. 113 | func (l binaryFreeList) Uint64(r io.Reader, byteOrder binary.ByteOrder) (uint64, error) { 114 | buf := l.Borrow()[:8] 115 | if _, err := io.ReadFull(r, buf); err != nil { 116 | l.Return(buf) 117 | return 0, err 118 | } 119 | rv := byteOrder.Uint64(buf) 120 | l.Return(buf) 121 | return rv, nil 122 | } 123 | 124 | // PutUint8 copies the provided uint8 into a buffer from the free list and 125 | // writes the resulting byte to the given writer. 126 | func (l binaryFreeList) PutUint8(w io.Writer, val uint8) error { 127 | buf := l.Borrow()[:1] 128 | buf[0] = val 129 | _, err := w.Write(buf) 130 | l.Return(buf) 131 | return err 132 | } 133 | 134 | // PutUint16 serializes the provided uint16 using the given byte order into a 135 | // buffer from the free list and writes the resulting two bytes to the given 136 | // writer. 137 | func (l binaryFreeList) PutUint16(w io.Writer, byteOrder binary.ByteOrder, val uint16) error { 138 | buf := l.Borrow()[:2] 139 | byteOrder.PutUint16(buf, val) 140 | _, err := w.Write(buf) 141 | l.Return(buf) 142 | return err 143 | } 144 | 145 | // PutUint32 serializes the provided uint32 using the given byte order into a 146 | // buffer from the free list and writes the resulting four bytes to the given 147 | // writer. 148 | func (l binaryFreeList) PutUint32(w io.Writer, byteOrder binary.ByteOrder, val uint32) error { 149 | buf := l.Borrow()[:4] 150 | byteOrder.PutUint32(buf, val) 151 | _, err := w.Write(buf) 152 | l.Return(buf) 153 | return err 154 | } 155 | 156 | // PutUint64 serializes the provided uint64 using the given byte order into a 157 | // buffer from the free list and writes the resulting eight bytes to the given 158 | // writer. 159 | func (l binaryFreeList) PutUint64(w io.Writer, byteOrder binary.ByteOrder, val uint64) error { 160 | buf := l.Borrow()[:8] 161 | byteOrder.PutUint64(buf, val) 162 | _, err := w.Write(buf) 163 | l.Return(buf) 164 | return err 165 | } 166 | 167 | // binarySerializer provides a free list of buffers to use for serializing and 168 | // deserializing primitive integer values to and from io.Readers and io.Writers. 169 | var binarySerializer binaryFreeList = make(chan []byte, binaryFreeListMaxItems) 170 | 171 | // ReadVarInt reads a variable length integer from r and returns it as a uint64. 172 | func ReadVarInt(r io.Reader) (uint64, error) { 173 | discriminant, err := binarySerializer.Uint8(r) 174 | if err != nil { 175 | return 0, err 176 | } 177 | 178 | var rv uint64 179 | switch discriminant { 180 | case 0xff: 181 | sv, err := binarySerializer.Uint64(r, littleEndian) 182 | if err != nil { 183 | return 0, err 184 | } 185 | rv = sv 186 | 187 | // The encoding is not canonical if the value could have been 188 | // encoded using fewer bytes. 189 | min := uint64(0x100000000) 190 | if rv < min { 191 | return 0, fmt.Errorf("%s: %s", "ReadVarInt", fmt.Sprintf("errNonCanonicalVarInt: %v %v %v", rv, discriminant, min)) 192 | } 193 | 194 | case 0xfe: 195 | sv, err := binarySerializer.Uint32(r, littleEndian) 196 | if err != nil { 197 | return 0, err 198 | } 199 | rv = uint64(sv) 200 | 201 | // The encoding is not canonical if the value could have been 202 | // encoded using fewer bytes. 203 | min := uint64(0x10000) 204 | if rv < min { 205 | return 0, fmt.Errorf("%s: %s", "ReadVarInt", fmt.Sprintf("errNonCanonicalVarInt: %v %v %v", rv, discriminant, min)) 206 | } 207 | 208 | case 0xfd: 209 | sv, err := binarySerializer.Uint16(r, littleEndian) 210 | if err != nil { 211 | return 0, err 212 | } 213 | rv = uint64(sv) 214 | 215 | // The encoding is not canonical if the value could have been 216 | // encoded using fewer bytes. 217 | min := uint64(0xfd) 218 | if rv < min { 219 | return 0, fmt.Errorf("%s: %s", "ReadVarInt", fmt.Sprintf("errNonCanonicalVarInt: %v %v %v", rv, discriminant, min)) 220 | } 221 | 222 | default: 223 | rv = uint64(discriminant) 224 | } 225 | 226 | return rv, nil 227 | } 228 | 229 | // WriteVarInt serializes val to w using a variable number of bytes depending 230 | // on its value. 231 | func WriteVarInt(w io.Writer, val uint64) error { 232 | if val < 0xfd { 233 | return binarySerializer.PutUint8(w, uint8(val)) 234 | } 235 | 236 | if val <= math.MaxUint16 { 237 | err := binarySerializer.PutUint8(w, 0xfd) 238 | if err != nil { 239 | return err 240 | } 241 | return binarySerializer.PutUint16(w, littleEndian, uint16(val)) 242 | } 243 | 244 | if val <= math.MaxUint32 { 245 | err := binarySerializer.PutUint8(w, 0xfe) 246 | if err != nil { 247 | return err 248 | } 249 | return binarySerializer.PutUint32(w, littleEndian, uint32(val)) 250 | } 251 | 252 | err := binarySerializer.PutUint8(w, 0xff) 253 | if err != nil { 254 | return err 255 | } 256 | return binarySerializer.PutUint64(w, littleEndian, val) 257 | } 258 | 259 | // VarIntSerializeSize returns the number of bytes it would take to serialize 260 | // val as a variable length integer. 261 | func VarIntSerializeSize(val uint64) int { 262 | // The value is small enough to be represented by itself, so it's 263 | // just 1 byte. 264 | if val < 0xfd { 265 | return 1 266 | } 267 | 268 | // Discriminant 1 byte plus 2 bytes for the uint16. 269 | if val <= math.MaxUint16 { 270 | return 3 271 | } 272 | 273 | // Discriminant 1 byte plus 4 bytes for the uint32. 274 | if val <= math.MaxUint32 { 275 | return 5 276 | } 277 | 278 | // Discriminant 1 byte plus 8 bytes for the uint64. 279 | return 9 280 | } 281 | 282 | // ReadVarBytes reads a variable length byte array. A byte array is encoded 283 | // as a varInt containing the length of the array followed by the bytes 284 | // themselves. An error is returned if the length is greater than the 285 | // passed maxAllowed parameter which helps protect against memory exhaustion 286 | // attacks and forced panics thorugh malformed messages. The fieldName 287 | // parameter is only used for the error message so it provides more context in 288 | // the error. 289 | func ReadVarBytes(r io.Reader, maxAllowed uint32, 290 | fieldName string) ([]byte, error) { 291 | 292 | count, err := ReadVarInt(r) 293 | if err != nil { 294 | return nil, err 295 | } 296 | 297 | b := make([]byte, count) 298 | _, err = io.ReadFull(r, b) 299 | if err != nil { 300 | return nil, err 301 | } 302 | return b, nil 303 | } 304 | 305 | // WriteVarBytes serializes a variable length byte array to w as a varInt 306 | // containing the number of bytes, followed by the bytes themselves. 307 | func WriteVarBytes(w io.Writer, bytes []byte) error { 308 | slen := uint64(len(bytes)) 309 | err := WriteVarInt(w, slen) 310 | if err != nil { 311 | return err 312 | } 313 | 314 | _, err = w.Write(bytes) 315 | if err != nil { 316 | return err 317 | } 318 | return nil 319 | } 320 | 321 | // randomUint64 returns a cryptographically random uint64 value. This 322 | // unexported version takes a reader primarily to ensure the error paths 323 | // can be properly tested by passing a fake reader in the tests. 324 | func randomUint64(r io.Reader) (uint64, error) { 325 | rv, err := binarySerializer.Uint64(r, bigEndian) 326 | if err != nil { 327 | return 0, err 328 | } 329 | return rv, nil 330 | } 331 | 332 | // RandomUint64 returns a cryptographically random uint64 value. 333 | func RandomUint64() (uint64, error) { 334 | return randomUint64(rand.Reader) 335 | } 336 | -------------------------------------------------------------------------------- /rangeproof.go: -------------------------------------------------------------------------------- 1 | package zksigma 2 | 3 | import ( 4 | "bytes" 5 | "crypto/rand" 6 | "crypto/sha256" 7 | "fmt" 8 | "math/big" 9 | "sync" 10 | 11 | "github.com/mit-dci/zksigma/wire" 12 | ) 13 | 14 | // The following was copy-pasted from zkLedger's original implementation by Willy (github.com/wrv) 15 | // TODO: replace rangeproofs of zkLedger with bulletproofs, eventually 16 | 17 | /////////////////////// 18 | // RANGE PROOFS 19 | 20 | type rangeProofTuple struct { 21 | C ECPoint 22 | S *big.Int 23 | } 24 | 25 | // RangeProof 26 | // Implementation details from: 27 | // https://blockstream.com/bitcoin17-final41.pdf 28 | // NOTE: To be consistent with our use of Pedersen commitments, we switch the G and H values 29 | // from the above description 30 | // 31 | // Takes in a value and randomness used in a commitment, and produces a proof that 32 | // our value is in range 2^64. 33 | // Range proofs uses ring signatures from Chameleon hashes and Pedersen Commitments 34 | // to do commitments on the bitwise decomposition of our value. 35 | // 36 | type RangeProof struct { 37 | ProofAggregate ECPoint 38 | ProofE *big.Int 39 | ProofTuples []rangeProofTuple 40 | } 41 | 42 | type proverInternalData struct { 43 | Rpoints []ECPoint 44 | Bpoints []ECPoint 45 | kScalars []*big.Int 46 | vScalars []*big.Int 47 | } 48 | 49 | // proofGenA takes in a waitgroup, index and bit 50 | // returns an Rpoint and Cpoint, and the k value bigint 51 | func proofGenA(zkpcp ZKPCurveParams, 52 | wg *sync.WaitGroup, idx int, bit bool, s *proverInternalData) error { 53 | 54 | defer wg.Done() 55 | var err error 56 | 57 | // R := s.Rpoints[idx] 58 | // B := s.Bpoints[idx] 59 | // k := stuff.kScalars[index] 60 | // v := stuff.vScalars[index] 61 | 62 | if !bit { // If bit is 0, just make a random R = k*H 63 | s.kScalars[idx], err = rand.Int(rand.Reader, zkpcp.C.Params().N) // random k 64 | if err != nil { 65 | return err 66 | } 67 | s.Rpoints[idx] = zkpcp.Mult(zkpcp.H, s.kScalars[idx]) // R is k * H 68 | } else { // if bit is 1, actually do stuff 69 | 70 | // get a random ri 71 | s.vScalars[idx], err = rand.Int(rand.Reader, zkpcp.C.Params().N) 72 | if err != nil { 73 | return err 74 | } 75 | // get R as H*ri... what is KC..? 76 | s.Rpoints[idx] = zkpcp.Mult(zkpcp.H, s.vScalars[idx]) 77 | 78 | // B is htothe[index] plus partial R 79 | s.Bpoints[idx].X, s.Bpoints[idx].Y = 80 | zkpcp.C.Add(zkpcp.HPoints[idx].X, zkpcp.HPoints[idx].Y, 81 | s.Rpoints[idx].X, s.Rpoints[idx].Y) 82 | 83 | // random k 84 | s.kScalars[idx], err = rand.Int(rand.Reader, zkpcp.C.Params().N) 85 | if err != nil { 86 | return err 87 | } 88 | 89 | // make k*H for hashing 90 | temp := zkpcp.Mult(zkpcp.H, s.kScalars[idx]) 91 | 92 | // Hash of temp point (why the whole thing..? 93 | hash := sha256.Sum256(append(temp.X.Bytes(), temp.Y.Bytes()...)) 94 | ei := new(big.Int).SetBytes(hash[:]) 95 | ei.Mod(ei, zkpcp.C.Params().N) 96 | s.Rpoints[idx].X, s.Rpoints[idx].Y = 97 | zkpcp.C.ScalarMult(s.Bpoints[idx].X, s.Bpoints[idx].Y, ei.Bytes()) 98 | } 99 | // fmt.Printf("loop %d\n", idx) 100 | 101 | return nil 102 | } 103 | 104 | // proofGenB takes waitgroup, index, bit, along with the data to operate on 105 | func proofGenB(zkpcp ZKPCurveParams, 106 | wg *sync.WaitGroup, idx int, bit bool, e0 *big.Int, data *proverInternalData) error { 107 | 108 | defer wg.Done() 109 | 110 | if !bit { 111 | // choose a random value from the integers mod prime 112 | j, err := rand.Int(rand.Reader, zkpcp.C.Params().N) 113 | if err != nil { 114 | return err 115 | } 116 | 117 | m2 := new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(idx)), zkpcp.C.Params().N) 118 | // m2 := big.NewInt(1 << uint(idx)) 119 | em2 := new(big.Int).Mul(e0, m2) 120 | em2.Mod(em2, zkpcp.C.Params().N) 121 | 122 | rhsX, rhsY := zkpcp.C.ScalarBaseMult(em2.Bytes()) 123 | 124 | lhs := zkpcp.Mult(zkpcp.H, j) 125 | 126 | totX, totY := zkpcp.C.Add(lhs.X, lhs.Y, rhsX, rhsY) 127 | 128 | hash := sha256.Sum256(append(totX.Bytes(), totY.Bytes()...)) 129 | ei := new(big.Int).SetBytes(hash[:]) // get ei 130 | ei.Mod(ei, zkpcp.C.Params().N) 131 | 132 | inverseEI := new(big.Int).ModInverse(ei, zkpcp.C.Params().N) 133 | 134 | data.vScalars[idx] = new(big.Int).Mul(inverseEI, data.kScalars[idx]) 135 | 136 | // set the C point for this index to R* inv ei 137 | data.Bpoints[idx] = zkpcp.Mult(data.Rpoints[idx], inverseEI) 138 | 139 | // s = k + (kValues[i] * e0) * inverse ei 140 | data.kScalars[idx] = j.Add( 141 | j, new(big.Int).Mul(data.kScalars[idx], new(big.Int).Mul(e0, inverseEI))) 142 | 143 | } else { // bit is 1, don't do anything 144 | // s is k + e0*v 145 | 146 | data.kScalars[idx] = new(big.Int).Add( 147 | data.kScalars[idx], new(big.Int).Mul(e0, data.vScalars[idx])) 148 | } 149 | 150 | return nil 151 | } 152 | 153 | // NewRangeProof generates a range proof for the given value 154 | func NewRangeProof(zkpcp ZKPCurveParams, value *big.Int) (*RangeProof, *big.Int, error) { 155 | proof := RangeProof{} 156 | 157 | // extend or truncate our value to 64 bits, which is the range we are proving 158 | // If our value is in range, then sum of commitments would equal original commitment 159 | // else, because of truncation, it will be deemed out of range not be equal 160 | 161 | if value.Cmp(big.NewInt(1099511627776)) == 1 { 162 | return nil, nil, fmt.Errorf("val %s too big, can only prove up to 1099511627776\n", value.String()) 163 | } 164 | 165 | proofSize := 40 166 | // check to see if our value is out of range 167 | if proofSize > 40 || value.Cmp(BigZero) == -1 { 168 | //if so, then we can't play 169 | return nil, nil, fmt.Errorf("** Trying to get a value that is out of range! Range Proof will not work!\n") 170 | } 171 | 172 | stuff := new(proverInternalData) 173 | 174 | stuff.kScalars = make([]*big.Int, proofSize) 175 | stuff.Rpoints = make([]ECPoint, proofSize) 176 | stuff.Bpoints = make([]ECPoint, proofSize) 177 | stuff.vScalars = make([]*big.Int, proofSize) 178 | 179 | vTotal := big.NewInt(0) 180 | proof.ProofTuples = make([]rangeProofTuple, proofSize) 181 | 182 | // do the loop bValue times 183 | var wg sync.WaitGroup 184 | wg.Add(proofSize) 185 | for i := 0; i < proofSize; i++ { 186 | // TODO: Check errors 187 | go proofGenA(zkpcp, &wg, i, value.Bit(i) == 1, stuff) 188 | } 189 | wg.Wait() 190 | 191 | // hash concat of all R values 192 | rHash := sha256.New() 193 | for _, rvalue := range stuff.Rpoints { 194 | rHash.Write(rvalue.X.Bytes()) 195 | rHash.Write(rvalue.Y.Bytes()) 196 | } 197 | hashed := rHash.Sum(nil) 198 | 199 | e0 := new(big.Int).SetBytes(hashed[:]) 200 | e0.Mod(e0, zkpcp.C.Params().N) 201 | 202 | var AggregatePoint ECPoint 203 | AggregatePoint.X = new(big.Int) 204 | AggregatePoint.Y = new(big.Int) 205 | 206 | // go through all 64 part B 207 | wg.Add(proofSize) 208 | for i := 0; i < proofSize; i++ { 209 | // TODO: Check errors 210 | go proofGenB(zkpcp, 211 | &wg, i, value.Bit(i) == 1, e0, stuff) 212 | } 213 | wg.Wait() 214 | 215 | for i := 0; i < proofSize; i++ { 216 | // add up to get vTotal scalar 217 | vTotal.Add(vTotal, stuff.vScalars[i]) 218 | 219 | // add points to get AggregatePoint 220 | AggregatePoint = zkpcp.Add(AggregatePoint, stuff.Bpoints[i]) 221 | 222 | // copy data to ProofTuples 223 | proof.ProofTuples[i].C = stuff.Bpoints[i] 224 | proof.ProofTuples[i].S = stuff.kScalars[i] 225 | } 226 | 227 | proof.ProofE = e0 228 | proof.ProofAggregate = AggregatePoint 229 | 230 | return &proof, vTotal, nil 231 | } 232 | 233 | type verifyTuple struct { 234 | index int 235 | Rpoint ECPoint 236 | } 237 | 238 | // give it a proof tuple, proofE. Get back an Rpoint, and a Cpoint 239 | func verifyGen(zkpcp ZKPCurveParams, 240 | idx int, proofE *big.Int, rpt rangeProofTuple, retbox chan verifyTuple) { 241 | 242 | lhs := zkpcp.Mult(zkpcp.H, rpt.S) 243 | 244 | rhs2 := zkpcp.Add(rpt.C, zkpcp.Neg(zkpcp.HPoints[idx])) 245 | 246 | rhsXYNeg := zkpcp.Neg(zkpcp.Mult(rhs2, proofE)) 247 | 248 | //s_i * G - e_0 * (C_i - 2^i * H) 249 | tot := zkpcp.Add(lhs, rhsXYNeg) 250 | 251 | hash := sha256.Sum256(append(tot.X.Bytes(), tot.Y.Bytes()...)) 252 | 253 | e1 := new(big.Int).SetBytes(hash[:]) 254 | 255 | var result verifyTuple 256 | result.index = idx 257 | result.Rpoint = zkpcp.Mult(rpt.C, e1) 258 | 259 | retbox <- result 260 | } 261 | 262 | func (proof *RangeProof) Verify(zkpcp ZKPCurveParams, comm ECPoint) (bool, error) { 263 | if proof == nil { 264 | return false, &errorProof{"RangeProof.Verify", fmt.Sprintf("passed proof is nil")} 265 | } 266 | 267 | proofs := proof.ProofTuples 268 | 269 | proofLength := len(proofs) 270 | 271 | Rpoints := make([]ECPoint, len(proofs)) 272 | 273 | totalPoint := ECPoint{big.NewInt(0), big.NewInt(0)} 274 | 275 | resultBox := make(chan verifyTuple, 10) // doubt we'll use even 1 276 | 277 | for i := 0; i < proofLength; i++ { 278 | // check that proofs are non-nil 279 | if proof.ProofTuples[i].C.X == nil { 280 | return false, &errorProof{"RangeProof.Verify", fmt.Sprintf("entry %d has nil point", i)} 281 | } 282 | if proof.ProofTuples[i].S == nil { 283 | return false, &errorProof{"RangeProof.Verify", fmt.Sprintf("entry %d has nil scalar", i)} 284 | 285 | } 286 | 287 | // give proof to the verify gorouting 288 | go verifyGen(zkpcp, i, proof.ProofE, proof.ProofTuples[i], resultBox) 289 | } 290 | 291 | for i := 0; i < proofLength; i++ { 292 | result := <-resultBox 293 | 294 | // only reason we do this is for the hash of the point. 295 | // could do something commutative here too? 296 | Rpoints[result.index] = result.Rpoint 297 | 298 | // add to totalpoint here (commutative) 299 | totalPoint = zkpcp.Add(totalPoint, proof.ProofTuples[i].C) 300 | } 301 | 302 | rHash := sha256.New() 303 | for _, rpoint := range Rpoints { 304 | rHash.Write(rpoint.X.Bytes()) 305 | rHash.Write(rpoint.Y.Bytes()) 306 | } 307 | calculatedE0 := rHash.Sum(nil) 308 | 309 | if proof.ProofE.Cmp(new(big.Int).SetBytes(calculatedE0[:])) != 0 { 310 | return false, &errorProof{"RangeProof.Verify", fmt.Sprintf("calculatedE0 does not match")} 311 | } 312 | 313 | if !totalPoint.Equal(proof.ProofAggregate) { 314 | return false, &errorProof{"RangeProof.Verify", fmt.Sprintf("ProofAggregate does not match totalPoint")} 315 | } 316 | 317 | if !comm.Equal(totalPoint) { 318 | return false, &errorProof{"RangeProof.Verify", fmt.Sprintf("ProofAggregate does not match commitment")} 319 | } 320 | 321 | return true, nil 322 | } 323 | 324 | // Bytes returns a byte slice with a serialized representation of RangeProof proof 325 | func (proof *RangeProof) Bytes() []byte { 326 | var buf bytes.Buffer 327 | 328 | WriteECPoint(&buf, proof.ProofAggregate) 329 | WriteBigInt(&buf, proof.ProofE) 330 | wire.WriteVarInt(&buf, uint64(len(proof.ProofTuples))) 331 | for _, t := range proof.ProofTuples { 332 | WriteECPoint(&buf, t.C) 333 | WriteBigInt(&buf, t.S) 334 | } 335 | 336 | return buf.Bytes() 337 | } 338 | 339 | // NewRangeProofFromBytes returns a RangeProof generated from the 340 | // deserialization of byte slice b 341 | func NewRangeProofFromBytes(b []byte) (*RangeProof, error) { 342 | proof := new(RangeProof) 343 | buf := bytes.NewBuffer(b) 344 | 345 | proof.ProofAggregate, _ = ReadECPoint(buf) 346 | proof.ProofE, _ = ReadBigInt(buf) 347 | numTuples, _ := wire.ReadVarInt(buf) 348 | proof.ProofTuples = make([]rangeProofTuple, numTuples) 349 | for i := uint64(0); i < numTuples; i++ { 350 | proof.ProofTuples[i] = rangeProofTuple{} 351 | proof.ProofTuples[i].C, _ = ReadECPoint(buf) 352 | proof.ProofTuples[i].S, _ = ReadBigInt(buf) 353 | } 354 | 355 | return proof, nil 356 | } 357 | -------------------------------------------------------------------------------- /btcec/signature.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013-2017 The btcsuite developers 2 | // Use of this source code is governed by an ISC 3 | // license that can be found in the LICENSE file. 4 | 5 | package btcec 6 | 7 | import ( 8 | "bytes" 9 | "crypto/ecdsa" 10 | "crypto/elliptic" 11 | "crypto/hmac" 12 | "crypto/sha256" 13 | "errors" 14 | "fmt" 15 | "hash" 16 | "math/big" 17 | ) 18 | 19 | // Errors returned by canonicalPadding. 20 | var ( 21 | errNegativeValue = errors.New("value may be interpreted as negative") 22 | errExcessivelyPaddedValue = errors.New("value is excessively padded") 23 | ) 24 | 25 | // Signature is a type representing an ecdsa signature. 26 | type Signature struct { 27 | R *big.Int 28 | S *big.Int 29 | } 30 | 31 | var ( 32 | // Used in RFC6979 implementation when testing the nonce for correctness 33 | one = big.NewInt(1) 34 | 35 | // oneInitializer is used to fill a byte slice with byte 0x01. It is provided 36 | // here to avoid the need to create it multiple times. 37 | oneInitializer = []byte{0x01} 38 | ) 39 | 40 | // Serialize returns the ECDSA signature in the more strict DER format. Note 41 | // that the serialized bytes returned do not include the appended hash type 42 | // used in Bitcoin signature scripts. 43 | // 44 | // encoding/asn1 is broken so we hand roll this output: 45 | // 46 | // 0x30 0x02 r 0x02 s 47 | func (sig *Signature) Serialize() []byte { 48 | // low 'S' malleability breaker 49 | sigS := sig.S 50 | if sigS.Cmp(S256().halfOrder) == 1 { 51 | sigS = new(big.Int).Sub(S256().N, sigS) 52 | } 53 | // Ensure the encoded bytes for the r and s values are canonical and 54 | // thus suitable for DER encoding. 55 | rb := canonicalizeInt(sig.R) 56 | sb := canonicalizeInt(sigS) 57 | 58 | // total length of returned signature is 1 byte for each magic and 59 | // length (6 total), plus lengths of r and s 60 | length := 6 + len(rb) + len(sb) 61 | b := make([]byte, length) 62 | 63 | b[0] = 0x30 64 | b[1] = byte(length - 2) 65 | b[2] = 0x02 66 | b[3] = byte(len(rb)) 67 | offset := copy(b[4:], rb) + 4 68 | b[offset] = 0x02 69 | b[offset+1] = byte(len(sb)) 70 | copy(b[offset+2:], sb) 71 | return b 72 | } 73 | 74 | // Verify calls ecdsa.Verify to verify the signature of hash using the public 75 | // key. It returns true if the signature is valid, false otherwise. 76 | func (sig *Signature) Verify(hash []byte, pubKey *PublicKey) bool { 77 | return ecdsa.Verify(pubKey.ToECDSA(), hash, sig.R, sig.S) 78 | } 79 | 80 | // IsEqual compares this Signature instance to the one passed, returning true 81 | // if both Signatures are equivalent. A signature is equivalent to another, if 82 | // they both have the same scalar value for R and S. 83 | func (sig *Signature) IsEqual(otherSig *Signature) bool { 84 | return sig.R.Cmp(otherSig.R) == 0 && 85 | sig.S.Cmp(otherSig.S) == 0 86 | } 87 | 88 | func parseSig(sigStr []byte, curve elliptic.Curve, der bool) (*Signature, error) { 89 | // Originally this code used encoding/asn1 in order to parse the 90 | // signature, but a number of problems were found with this approach. 91 | // Despite the fact that signatures are stored as DER, the difference 92 | // between go's idea of a bignum (and that they have sign) doesn't agree 93 | // with the openssl one (where they do not). The above is true as of 94 | // Go 1.1. In the end it was simpler to rewrite the code to explicitly 95 | // understand the format which is this: 96 | // 0x30 <0x02> 0x2 97 | // . 98 | 99 | signature := &Signature{} 100 | 101 | // minimal message is when both numbers are 1 bytes. adding up to: 102 | // 0x30 + len + 0x02 + 0x01 + + 0x2 + 0x01 + 103 | if len(sigStr) < 8 { 104 | return nil, errors.New("malformed signature: too short") 105 | } 106 | // 0x30 107 | index := 0 108 | if sigStr[index] != 0x30 { 109 | return nil, errors.New("malformed signature: no header magic") 110 | } 111 | index++ 112 | // length of remaining message 113 | siglen := sigStr[index] 114 | index++ 115 | if int(siglen+2) > len(sigStr) { 116 | return nil, errors.New("malformed signature: bad length") 117 | } 118 | // trim the slice we're working on so we only look at what matters. 119 | sigStr = sigStr[:siglen+2] 120 | 121 | // 0x02 122 | if sigStr[index] != 0x02 { 123 | return nil, 124 | errors.New("malformed signature: no 1st int marker") 125 | } 126 | index++ 127 | 128 | // Length of signature R. 129 | rLen := int(sigStr[index]) 130 | // must be positive, must be able to fit in another 0x2, 131 | // hence the -3. We assume that the length must be at least one byte. 132 | index++ 133 | if rLen <= 0 || rLen > len(sigStr)-index-3 { 134 | return nil, errors.New("malformed signature: bogus R length") 135 | } 136 | 137 | // Then R itself. 138 | rBytes := sigStr[index : index+rLen] 139 | if der { 140 | switch err := canonicalPadding(rBytes); err { 141 | case errNegativeValue: 142 | return nil, errors.New("signature R is negative") 143 | case errExcessivelyPaddedValue: 144 | return nil, errors.New("signature R is excessively padded") 145 | } 146 | } 147 | signature.R = new(big.Int).SetBytes(rBytes) 148 | index += rLen 149 | // 0x02. length already checked in previous if. 150 | if sigStr[index] != 0x02 { 151 | return nil, errors.New("malformed signature: no 2nd int marker") 152 | } 153 | index++ 154 | 155 | // Length of signature S. 156 | sLen := int(sigStr[index]) 157 | index++ 158 | // S should be the rest of the string. 159 | if sLen <= 0 || sLen > len(sigStr)-index { 160 | return nil, errors.New("malformed signature: bogus S length") 161 | } 162 | 163 | // Then S itself. 164 | sBytes := sigStr[index : index+sLen] 165 | if der { 166 | switch err := canonicalPadding(sBytes); err { 167 | case errNegativeValue: 168 | return nil, errors.New("signature S is negative") 169 | case errExcessivelyPaddedValue: 170 | return nil, errors.New("signature S is excessively padded") 171 | } 172 | } 173 | signature.S = new(big.Int).SetBytes(sBytes) 174 | index += sLen 175 | 176 | // sanity check length parsing 177 | if index != len(sigStr) { 178 | return nil, fmt.Errorf("malformed signature: bad final length %v != %v", 179 | index, len(sigStr)) 180 | } 181 | 182 | // Verify also checks this, but we can be more sure that we parsed 183 | // correctly if we verify here too. 184 | // FWIW the ecdsa spec states that R and S must be | 1, N - 1 | 185 | // but crypto/ecdsa only checks for Sign != 0. Mirror that. 186 | if signature.R.Sign() != 1 { 187 | return nil, errors.New("signature R isn't 1 or more") 188 | } 189 | if signature.S.Sign() != 1 { 190 | return nil, errors.New("signature S isn't 1 or more") 191 | } 192 | if signature.R.Cmp(curve.Params().N) >= 0 { 193 | return nil, errors.New("signature R is >= curve.N") 194 | } 195 | if signature.S.Cmp(curve.Params().N) >= 0 { 196 | return nil, errors.New("signature S is >= curve.N") 197 | } 198 | 199 | return signature, nil 200 | } 201 | 202 | // ParseSignature parses a signature in BER format for the curve type `curve' 203 | // into a Signature type, perfoming some basic sanity checks. If parsing 204 | // according to the more strict DER format is needed, use ParseDERSignature. 205 | func ParseSignature(sigStr []byte, curve elliptic.Curve) (*Signature, error) { 206 | return parseSig(sigStr, curve, false) 207 | } 208 | 209 | // ParseDERSignature parses a signature in DER format for the curve type 210 | // `curve` into a Signature type. If parsing according to the less strict 211 | // BER format is needed, use ParseSignature. 212 | func ParseDERSignature(sigStr []byte, curve elliptic.Curve) (*Signature, error) { 213 | return parseSig(sigStr, curve, true) 214 | } 215 | 216 | // canonicalizeInt returns the bytes for the passed big integer adjusted as 217 | // necessary to ensure that a big-endian encoded integer can't possibly be 218 | // misinterpreted as a negative number. This can happen when the most 219 | // significant bit is set, so it is padded by a leading zero byte in this case. 220 | // Also, the returned bytes will have at least a single byte when the passed 221 | // value is 0. This is required for DER encoding. 222 | func canonicalizeInt(val *big.Int) []byte { 223 | b := val.Bytes() 224 | if len(b) == 0 { 225 | b = []byte{0x00} 226 | } 227 | if b[0]&0x80 != 0 { 228 | paddedBytes := make([]byte, len(b)+1) 229 | copy(paddedBytes[1:], b) 230 | b = paddedBytes 231 | } 232 | return b 233 | } 234 | 235 | // canonicalPadding checks whether a big-endian encoded integer could 236 | // possibly be misinterpreted as a negative number (even though OpenSSL 237 | // treats all numbers as unsigned), or if there is any unnecessary 238 | // leading zero padding. 239 | func canonicalPadding(b []byte) error { 240 | switch { 241 | case b[0]&0x80 == 0x80: 242 | return errNegativeValue 243 | case len(b) > 1 && b[0] == 0x00 && b[1]&0x80 != 0x80: 244 | return errExcessivelyPaddedValue 245 | default: 246 | return nil 247 | } 248 | } 249 | 250 | // hashToInt converts a hash value to an integer. There is some disagreement 251 | // about how this is done. [NSA] suggests that this is done in the obvious 252 | // manner, but [SECG] truncates the hash to the bit-length of the curve order 253 | // first. We follow [SECG] because that's what OpenSSL does. Additionally, 254 | // OpenSSL right shifts excess bits from the number if the hash is too large 255 | // and we mirror that too. 256 | // This is borrowed from crypto/ecdsa. 257 | func hashToInt(hash []byte, c elliptic.Curve) *big.Int { 258 | orderBits := c.Params().N.BitLen() 259 | orderBytes := (orderBits + 7) / 8 260 | if len(hash) > orderBytes { 261 | hash = hash[:orderBytes] 262 | } 263 | 264 | ret := new(big.Int).SetBytes(hash) 265 | excess := len(hash)*8 - orderBits 266 | if excess > 0 { 267 | ret.Rsh(ret, uint(excess)) 268 | } 269 | return ret 270 | } 271 | 272 | // recoverKeyFromSignature recovers a public key from the signature "sig" on the 273 | // given message hash "msg". Based on the algorithm found in section 5.1.5 of 274 | // SEC 1 Ver 2.0, page 47-48 (53 and 54 in the pdf). This performs the details 275 | // in the inner loop in Step 1. The counter provided is actually the j parameter 276 | // of the loop * 2 - on the first iteration of j we do the R case, else the -R 277 | // case in step 1.6. This counter is used in the bitcoin compressed signature 278 | // format and thus we match bitcoind's behaviour here. 279 | func recoverKeyFromSignature(curve *KoblitzCurve, sig *Signature, msg []byte, 280 | iter int, doChecks bool) (*PublicKey, error) { 281 | // 1.1 x = (n * i) + r 282 | Rx := new(big.Int).Mul(curve.Params().N, 283 | new(big.Int).SetInt64(int64(iter/2))) 284 | Rx.Add(Rx, sig.R) 285 | if Rx.Cmp(curve.Params().P) != -1 { 286 | return nil, errors.New("calculated Rx is larger than curve P") 287 | } 288 | 289 | // convert 02 to point R. (step 1.2 and 1.3). If we are on an odd 290 | // iteration then 1.6 will be done with -R, so we calculate the other 291 | // term when uncompressing the point. 292 | Ry, err := decompressPoint(curve, Rx, iter%2 == 1) 293 | if err != nil { 294 | return nil, err 295 | } 296 | 297 | // 1.4 Check n*R is point at infinity 298 | if doChecks { 299 | nRx, nRy := curve.ScalarMult(Rx, Ry, curve.Params().N.Bytes()) 300 | if nRx.Sign() != 0 || nRy.Sign() != 0 { 301 | return nil, errors.New("n*R does not equal the point at infinity") 302 | } 303 | } 304 | 305 | // 1.5 calculate e from message using the same algorithm as ecdsa 306 | // signature calculation. 307 | e := hashToInt(msg, curve) 308 | 309 | // Step 1.6.1: 310 | // We calculate the two terms sR and eG separately multiplied by the 311 | // inverse of r (from the signature). We then add them to calculate 312 | // Q = r^-1(sR-eG) 313 | invr := new(big.Int).ModInverse(sig.R, curve.Params().N) 314 | 315 | // first term. 316 | invrS := new(big.Int).Mul(invr, sig.S) 317 | invrS.Mod(invrS, curve.Params().N) 318 | sRx, sRy := curve.ScalarMult(Rx, Ry, invrS.Bytes()) 319 | 320 | // second term. 321 | e.Neg(e) 322 | e.Mod(e, curve.Params().N) 323 | e.Mul(e, invr) 324 | e.Mod(e, curve.Params().N) 325 | minuseGx, minuseGy := curve.ScalarBaseMult(e.Bytes()) 326 | 327 | // TODO: this would be faster if we did a mult and add in one 328 | // step to prevent the jacobian conversion back and forth. 329 | Qx, Qy := curve.Add(sRx, sRy, minuseGx, minuseGy) 330 | 331 | return &PublicKey{ 332 | Curve: curve, 333 | X: Qx, 334 | Y: Qy, 335 | }, nil 336 | } 337 | 338 | // SignCompact produces a compact signature of the data in hash with the given 339 | // private key on the given koblitz curve. The isCompressed parameter should 340 | // be used to detail if the given signature should reference a compressed 341 | // public key or not. If successful the bytes of the compact signature will be 342 | // returned in the format: 343 | // <(byte of 27+public key solution)+4 if compressed >< padded bytes for signature R> 344 | // where the R and S parameters are padde up to the bitlengh of the curve. 345 | func SignCompact(curve *KoblitzCurve, key *PrivateKey, 346 | hash []byte, isCompressedKey bool) ([]byte, error) { 347 | sig, err := key.Sign(hash) 348 | if err != nil { 349 | return nil, err 350 | } 351 | 352 | // bitcoind checks the bit length of R and S here. The ecdsa signature 353 | // algorithm returns R and S mod N therefore they will be the bitsize of 354 | // the curve, and thus correctly sized. 355 | for i := 0; i < (curve.H+1)*2; i++ { 356 | pk, err := recoverKeyFromSignature(curve, sig, hash, i, true) 357 | if err == nil && pk.X.Cmp(key.X) == 0 && pk.Y.Cmp(key.Y) == 0 { 358 | result := make([]byte, 1, 2*curve.byteSize+1) 359 | result[0] = 27 + byte(i) 360 | if isCompressedKey { 361 | result[0] += 4 362 | } 363 | // Not sure this needs rounding but safer to do so. 364 | curvelen := (curve.BitSize + 7) / 8 365 | 366 | // Pad R and S to curvelen if needed. 367 | bytelen := (sig.R.BitLen() + 7) / 8 368 | if bytelen < curvelen { 369 | result = append(result, 370 | make([]byte, curvelen-bytelen)...) 371 | } 372 | result = append(result, sig.R.Bytes()...) 373 | 374 | bytelen = (sig.S.BitLen() + 7) / 8 375 | if bytelen < curvelen { 376 | result = append(result, 377 | make([]byte, curvelen-bytelen)...) 378 | } 379 | result = append(result, sig.S.Bytes()...) 380 | 381 | return result, nil 382 | } 383 | } 384 | 385 | return nil, errors.New("no valid solution for pubkey found") 386 | } 387 | 388 | // RecoverCompact verifies the compact signature "signature" of "hash" for the 389 | // Koblitz curve in "curve". If the signature matches then the recovered public 390 | // key will be returned as well as a boolen if the original key was compressed 391 | // or not, else an error will be returned. 392 | func RecoverCompact(curve *KoblitzCurve, signature, 393 | hash []byte) (*PublicKey, bool, error) { 394 | bitlen := (curve.BitSize + 7) / 8 395 | if len(signature) != 1+bitlen*2 { 396 | return nil, false, errors.New("invalid compact signature size") 397 | } 398 | 399 | iteration := int((signature[0] - 27) & ^byte(4)) 400 | 401 | // format is
402 | sig := &Signature{ 403 | R: new(big.Int).SetBytes(signature[1 : bitlen+1]), 404 | S: new(big.Int).SetBytes(signature[bitlen+1:]), 405 | } 406 | // The iteration used here was encoded 407 | key, err := recoverKeyFromSignature(curve, sig, hash, iteration, false) 408 | if err != nil { 409 | return nil, false, err 410 | } 411 | 412 | return key, ((signature[0] - 27) & 4) == 4, nil 413 | } 414 | 415 | // signRFC6979 generates a deterministic ECDSA signature according to RFC 6979 and BIP 62. 416 | func signRFC6979(privateKey *PrivateKey, hash []byte) (*Signature, error) { 417 | 418 | privkey := privateKey.ToECDSA() 419 | N := S256().N 420 | halfOrder := S256().halfOrder 421 | k := nonceRFC6979(privkey.D, hash) 422 | inv := new(big.Int).ModInverse(k, N) 423 | r, _ := privkey.Curve.ScalarBaseMult(k.Bytes()) 424 | if r.Cmp(N) == 1 { 425 | r.Sub(r, N) 426 | } 427 | 428 | if r.Sign() == 0 { 429 | return nil, errors.New("calculated R is zero") 430 | } 431 | 432 | e := hashToInt(hash, privkey.Curve) 433 | s := new(big.Int).Mul(privkey.D, r) 434 | s.Add(s, e) 435 | s.Mul(s, inv) 436 | s.Mod(s, N) 437 | 438 | if s.Cmp(halfOrder) == 1 { 439 | s.Sub(N, s) 440 | } 441 | if s.Sign() == 0 { 442 | return nil, errors.New("calculated S is zero") 443 | } 444 | return &Signature{R: r, S: s}, nil 445 | } 446 | 447 | // nonceRFC6979 generates an ECDSA nonce (`k`) deterministically according to RFC 6979. 448 | // It takes a 32-byte hash as an input and returns 32-byte nonce to be used in ECDSA algorithm. 449 | func nonceRFC6979(privkey *big.Int, hash []byte) *big.Int { 450 | 451 | curve := S256() 452 | q := curve.Params().N 453 | x := privkey 454 | alg := sha256.New 455 | 456 | qlen := q.BitLen() 457 | holen := alg().Size() 458 | rolen := (qlen + 7) >> 3 459 | bx := append(int2octets(x, rolen), bits2octets(hash, curve, rolen)...) 460 | 461 | // Step B 462 | v := bytes.Repeat(oneInitializer, holen) 463 | 464 | // Step C (Go zeroes the all allocated memory) 465 | k := make([]byte, holen) 466 | 467 | // Step D 468 | k = mac(alg, k, append(append(v, 0x00), bx...)) 469 | 470 | // Step E 471 | v = mac(alg, k, v) 472 | 473 | // Step F 474 | k = mac(alg, k, append(append(v, 0x01), bx...)) 475 | 476 | // Step G 477 | v = mac(alg, k, v) 478 | 479 | // Step H 480 | for { 481 | // Step H1 482 | var t []byte 483 | 484 | // Step H2 485 | for len(t)*8 < qlen { 486 | v = mac(alg, k, v) 487 | t = append(t, v...) 488 | } 489 | 490 | // Step H3 491 | secret := hashToInt(t, curve) 492 | if secret.Cmp(one) >= 0 && secret.Cmp(q) < 0 { 493 | return secret 494 | } 495 | k = mac(alg, k, append(v, 0x00)) 496 | v = mac(alg, k, v) 497 | } 498 | } 499 | 500 | // mac returns an HMAC of the given key and message. 501 | func mac(alg func() hash.Hash, k, m []byte) []byte { 502 | h := hmac.New(alg, k) 503 | h.Write(m) 504 | return h.Sum(nil) 505 | } 506 | 507 | // https://tools.ietf.org/html/rfc6979#section-2.3.3 508 | func int2octets(v *big.Int, rolen int) []byte { 509 | out := v.Bytes() 510 | 511 | // left pad with zeros if it's too short 512 | if len(out) < rolen { 513 | out2 := make([]byte, rolen) 514 | copy(out2[rolen-len(out):], out) 515 | return out2 516 | } 517 | 518 | // drop most significant bytes if it's too long 519 | if len(out) > rolen { 520 | out2 := make([]byte, rolen) 521 | copy(out2, out[len(out)-rolen:]) 522 | return out2 523 | } 524 | 525 | return out 526 | } 527 | 528 | // https://tools.ietf.org/html/rfc6979#section-2.3.4 529 | func bits2octets(in []byte, curve elliptic.Curve, rolen int) []byte { 530 | z1 := hashToInt(in, curve) 531 | z2 := new(big.Int).Sub(z1, curve.Params().N) 532 | if z2.Sign() < 0 { 533 | return int2octets(z1, rolen) 534 | } 535 | return int2octets(z2, rolen) 536 | } 537 | -------------------------------------------------------------------------------- /btcec/field_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013-2016 The btcsuite developers 2 | // Copyright (c) 2013-2016 Dave Collins 3 | // Use of this source code is governed by an ISC 4 | // license that can be found in the LICENSE file. 5 | 6 | package btcec 7 | 8 | import ( 9 | "reflect" 10 | "testing" 11 | ) 12 | 13 | // TestSetInt ensures that setting a field value to various native integers 14 | // works as expected. 15 | func TestSetInt(t *testing.T) { 16 | tests := []struct { 17 | in uint 18 | raw [10]uint32 19 | }{ 20 | {5, [10]uint32{5, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, 21 | // 2^26 22 | {67108864, [10]uint32{67108864, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, 23 | // 2^26 + 1 24 | {67108865, [10]uint32{67108865, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, 25 | // 2^32 - 1 26 | {4294967295, [10]uint32{4294967295, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, 27 | } 28 | 29 | t.Logf("Running %d tests", len(tests)) 30 | for i, test := range tests { 31 | f := new(fieldVal).SetInt(test.in) 32 | if !reflect.DeepEqual(f.n, test.raw) { 33 | t.Errorf("fieldVal.Set #%d wrong result\ngot: %v\n"+ 34 | "want: %v", i, f.n, test.raw) 35 | continue 36 | } 37 | } 38 | } 39 | 40 | // TestZero ensures that zeroing a field value zero works as expected. 41 | func TestZero(t *testing.T) { 42 | f := new(fieldVal).SetInt(2) 43 | f.Zero() 44 | for idx, rawInt := range f.n { 45 | if rawInt != 0 { 46 | t.Errorf("internal field integer at index #%d is not "+ 47 | "zero - got %d", idx, rawInt) 48 | } 49 | } 50 | } 51 | 52 | // TestIsZero ensures that checking if a field IsZero works as expected. 53 | func TestIsZero(t *testing.T) { 54 | f := new(fieldVal) 55 | if !f.IsZero() { 56 | t.Errorf("new field value is not zero - got %v (rawints %x)", f, 57 | f.n) 58 | } 59 | 60 | f.SetInt(1) 61 | if f.IsZero() { 62 | t.Errorf("field claims it's zero when it's not - got %v "+ 63 | "(raw rawints %x)", f, f.n) 64 | } 65 | 66 | f.Zero() 67 | if !f.IsZero() { 68 | t.Errorf("field claims it's not zero when it is - got %v "+ 69 | "(raw rawints %x)", f, f.n) 70 | } 71 | } 72 | 73 | // TestStringer ensures the stringer returns the appropriate hex string. 74 | func TestStringer(t *testing.T) { 75 | tests := []struct { 76 | in string 77 | expected string 78 | }{ 79 | {"0", "0000000000000000000000000000000000000000000000000000000000000000"}, 80 | {"1", "0000000000000000000000000000000000000000000000000000000000000001"}, 81 | {"a", "000000000000000000000000000000000000000000000000000000000000000a"}, 82 | {"b", "000000000000000000000000000000000000000000000000000000000000000b"}, 83 | {"c", "000000000000000000000000000000000000000000000000000000000000000c"}, 84 | {"d", "000000000000000000000000000000000000000000000000000000000000000d"}, 85 | {"e", "000000000000000000000000000000000000000000000000000000000000000e"}, 86 | {"f", "000000000000000000000000000000000000000000000000000000000000000f"}, 87 | {"f0", "00000000000000000000000000000000000000000000000000000000000000f0"}, 88 | // 2^26-1 89 | { 90 | "3ffffff", 91 | "0000000000000000000000000000000000000000000000000000000003ffffff", 92 | }, 93 | // 2^32-1 94 | { 95 | "ffffffff", 96 | "00000000000000000000000000000000000000000000000000000000ffffffff", 97 | }, 98 | // 2^64-1 99 | { 100 | "ffffffffffffffff", 101 | "000000000000000000000000000000000000000000000000ffffffffffffffff", 102 | }, 103 | // 2^96-1 104 | { 105 | "ffffffffffffffffffffffff", 106 | "0000000000000000000000000000000000000000ffffffffffffffffffffffff", 107 | }, 108 | // 2^128-1 109 | { 110 | "ffffffffffffffffffffffffffffffff", 111 | "00000000000000000000000000000000ffffffffffffffffffffffffffffffff", 112 | }, 113 | // 2^160-1 114 | { 115 | "ffffffffffffffffffffffffffffffffffffffff", 116 | "000000000000000000000000ffffffffffffffffffffffffffffffffffffffff", 117 | }, 118 | // 2^192-1 119 | { 120 | "ffffffffffffffffffffffffffffffffffffffffffffffff", 121 | "0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff", 122 | }, 123 | // 2^224-1 124 | { 125 | "ffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 126 | "00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 127 | }, 128 | // 2^256-4294968273 (the btcec prime, so should result in 0) 129 | { 130 | "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", 131 | "0000000000000000000000000000000000000000000000000000000000000000", 132 | }, 133 | // 2^256-4294968274 (the secp256k1 prime+1, so should result in 1) 134 | { 135 | "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", 136 | "0000000000000000000000000000000000000000000000000000000000000001", 137 | }, 138 | 139 | // Invalid hex 140 | {"g", "0000000000000000000000000000000000000000000000000000000000000000"}, 141 | {"1h", "0000000000000000000000000000000000000000000000000000000000000000"}, 142 | {"i1", "0000000000000000000000000000000000000000000000000000000000000000"}, 143 | } 144 | 145 | t.Logf("Running %d tests", len(tests)) 146 | for i, test := range tests { 147 | f := new(fieldVal).SetHex(test.in) 148 | result := f.String() 149 | if result != test.expected { 150 | t.Errorf("fieldVal.String #%d wrong result\ngot: %v\n"+ 151 | "want: %v", i, result, test.expected) 152 | continue 153 | } 154 | } 155 | } 156 | 157 | // TestNormalize ensures that normalizing the internal field words works as 158 | // expected. 159 | func TestNormalize(t *testing.T) { 160 | tests := []struct { 161 | raw [10]uint32 // Intentionally denormalized value 162 | normalized [10]uint32 // Normalized form of the raw value 163 | }{ 164 | { 165 | [10]uint32{0x00000005, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 166 | [10]uint32{0x00000005, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 167 | }, 168 | // 2^26 169 | { 170 | [10]uint32{0x04000000, 0x0, 0, 0, 0, 0, 0, 0, 0, 0}, 171 | [10]uint32{0x00000000, 0x1, 0, 0, 0, 0, 0, 0, 0, 0}, 172 | }, 173 | // 2^26 + 1 174 | { 175 | [10]uint32{0x04000001, 0x0, 0, 0, 0, 0, 0, 0, 0, 0}, 176 | [10]uint32{0x00000001, 0x1, 0, 0, 0, 0, 0, 0, 0, 0}, 177 | }, 178 | // 2^32 - 1 179 | { 180 | [10]uint32{0xffffffff, 0x00, 0, 0, 0, 0, 0, 0, 0, 0}, 181 | [10]uint32{0x03ffffff, 0x3f, 0, 0, 0, 0, 0, 0, 0, 0}, 182 | }, 183 | // 2^32 184 | { 185 | [10]uint32{0x04000000, 0x3f, 0, 0, 0, 0, 0, 0, 0, 0}, 186 | [10]uint32{0x00000000, 0x40, 0, 0, 0, 0, 0, 0, 0, 0}, 187 | }, 188 | // 2^32 + 1 189 | { 190 | [10]uint32{0x04000001, 0x3f, 0, 0, 0, 0, 0, 0, 0, 0}, 191 | [10]uint32{0x00000001, 0x40, 0, 0, 0, 0, 0, 0, 0, 0}, 192 | }, 193 | // 2^64 - 1 194 | { 195 | [10]uint32{0xffffffff, 0xffffffc0, 0xfc0, 0, 0, 0, 0, 0, 0, 0}, 196 | [10]uint32{0x03ffffff, 0x03ffffff, 0xfff, 0, 0, 0, 0, 0, 0, 0}, 197 | }, 198 | // 2^64 199 | { 200 | [10]uint32{0x04000000, 0x03ffffff, 0x0fff, 0, 0, 0, 0, 0, 0, 0}, 201 | [10]uint32{0x00000000, 0x00000000, 0x1000, 0, 0, 0, 0, 0, 0, 0}, 202 | }, 203 | // 2^64 + 1 204 | { 205 | [10]uint32{0x04000001, 0x03ffffff, 0x0fff, 0, 0, 0, 0, 0, 0, 0}, 206 | [10]uint32{0x00000001, 0x00000000, 0x1000, 0, 0, 0, 0, 0, 0, 0}, 207 | }, 208 | // 2^96 - 1 209 | { 210 | [10]uint32{0xffffffff, 0xffffffc0, 0xffffffc0, 0x3ffc0, 0, 0, 0, 0, 0, 0}, 211 | [10]uint32{0x03ffffff, 0x03ffffff, 0x03ffffff, 0x3ffff, 0, 0, 0, 0, 0, 0}, 212 | }, 213 | // 2^96 214 | { 215 | [10]uint32{0x04000000, 0x03ffffff, 0x03ffffff, 0x3ffff, 0, 0, 0, 0, 0, 0}, 216 | [10]uint32{0x00000000, 0x00000000, 0x00000000, 0x40000, 0, 0, 0, 0, 0, 0}, 217 | }, 218 | // 2^128 - 1 219 | { 220 | [10]uint32{0xffffffff, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffc0, 0, 0, 0, 0, 0}, 221 | [10]uint32{0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0xffffff, 0, 0, 0, 0, 0}, 222 | }, 223 | // 2^128 224 | { 225 | [10]uint32{0x04000000, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x0ffffff, 0, 0, 0, 0, 0}, 226 | [10]uint32{0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1000000, 0, 0, 0, 0, 0}, 227 | }, 228 | // 2^256 - 4294968273 (secp256k1 prime) 229 | { 230 | [10]uint32{0xfffffc2f, 0xffffff80, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0x3fffc0}, 231 | [10]uint32{0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000}, 232 | }, 233 | // Prime larger than P where both first and second words are larger 234 | // than P's first and second words 235 | { 236 | [10]uint32{0xfffffc30, 0xffffff86, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0x3fffc0}, 237 | [10]uint32{0x00000001, 0x00000006, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000}, 238 | }, 239 | // Prime larger than P where only the second word is larger 240 | // than P's second words. 241 | { 242 | [10]uint32{0xfffffc2a, 0xffffff87, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0x3fffc0}, 243 | [10]uint32{0x03fffffb, 0x00000006, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000}, 244 | }, 245 | // 2^256 - 1 246 | { 247 | [10]uint32{0xffffffff, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0xffffffc0, 0x3fffc0}, 248 | [10]uint32{0x000003d0, 0x00000040, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000}, 249 | }, 250 | // Prime with field representation such that the initial 251 | // reduction does not result in a carry to bit 256. 252 | // 253 | // 2^256 - 4294968273 (secp256k1 prime) 254 | { 255 | [10]uint32{0x03fffc2f, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003fffff}, 256 | [10]uint32{0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, 257 | }, 258 | // Prime larger than P that reduces to a value which is still 259 | // larger than P when it has a magnitude of 1 due to its first 260 | // word and does not result in a carry to bit 256. 261 | // 262 | // 2^256 - 4294968272 (secp256k1 prime + 1) 263 | { 264 | [10]uint32{0x03fffc30, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003fffff}, 265 | [10]uint32{0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, 266 | }, 267 | // Prime larger than P that reduces to a value which is still 268 | // larger than P when it has a magnitude of 1 due to its second 269 | // word and does not result in a carry to bit 256. 270 | // 271 | // 2^256 - 4227859409 (secp256k1 prime + 0x4000000) 272 | { 273 | [10]uint32{0x03fffc2f, 0x03ffffc0, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003fffff}, 274 | [10]uint32{0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, 275 | }, 276 | // Prime larger than P that reduces to a value which is still 277 | // larger than P when it has a magnitude of 1 due to a carry to 278 | // bit 256, but would not be without the carry. These values 279 | // come from the fact that P is 2^256 - 4294968273 and 977 is 280 | // the low order word in the internal field representation. 281 | // 282 | // 2^256 * 5 - ((4294968273 - (977+1)) * 4) 283 | { 284 | [10]uint32{0x03ffffff, 0x03fffeff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x0013fffff}, 285 | [10]uint32{0x00001314, 0x00000040, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000000}, 286 | }, 287 | // Prime larger than P that reduces to a value which is still 288 | // larger than P when it has a magnitude of 1 due to both a 289 | // carry to bit 256 and the first word. 290 | { 291 | [10]uint32{0x03fffc30, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x07ffffff, 0x003fffff}, 292 | [10]uint32{0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001}, 293 | }, 294 | // Prime larger than P that reduces to a value which is still 295 | // larger than P when it has a magnitude of 1 due to both a 296 | // carry to bit 256 and the second word. 297 | // 298 | { 299 | [10]uint32{0x03fffc2f, 0x03ffffc0, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x3ffffff, 0x07ffffff, 0x003fffff}, 300 | [10]uint32{0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000, 0x00000000, 0x00000001}, 301 | }, 302 | // Prime larger than P that reduces to a value which is still 303 | // larger than P when it has a magnitude of 1 due to a carry to 304 | // bit 256 and the first and second words. 305 | // 306 | { 307 | [10]uint32{0x03fffc30, 0x03ffffc0, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x07ffffff, 0x003fffff}, 308 | [10]uint32{0x00000001, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001}, 309 | }, 310 | } 311 | 312 | t.Logf("Running %d tests", len(tests)) 313 | for i, test := range tests { 314 | f := new(fieldVal) 315 | f.n = test.raw 316 | f.Normalize() 317 | if !reflect.DeepEqual(f.n, test.normalized) { 318 | t.Errorf("fieldVal.Normalize #%d wrong result\n"+ 319 | "got: %x\nwant: %x", i, f.n, test.normalized) 320 | continue 321 | } 322 | } 323 | } 324 | 325 | // TestIsOdd ensures that checking if a field value IsOdd works as expected. 326 | func TestIsOdd(t *testing.T) { 327 | tests := []struct { 328 | in string // hex encoded value 329 | expected bool // expected oddness 330 | }{ 331 | {"0", false}, 332 | {"1", true}, 333 | {"2", false}, 334 | // 2^32 - 1 335 | {"ffffffff", true}, 336 | // 2^64 - 2 337 | {"fffffffffffffffe", false}, 338 | // secp256k1 prime 339 | {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", true}, 340 | } 341 | 342 | t.Logf("Running %d tests", len(tests)) 343 | for i, test := range tests { 344 | f := new(fieldVal).SetHex(test.in) 345 | result := f.IsOdd() 346 | if result != test.expected { 347 | t.Errorf("fieldVal.IsOdd #%d wrong result\n"+ 348 | "got: %v\nwant: %v", i, result, test.expected) 349 | continue 350 | } 351 | } 352 | } 353 | 354 | // TestEquals ensures that checking two field values for equality via Equals 355 | // works as expected. 356 | func TestEquals(t *testing.T) { 357 | tests := []struct { 358 | in1 string // hex encoded value 359 | in2 string // hex encoded value 360 | expected bool // expected equality 361 | }{ 362 | {"0", "0", true}, 363 | {"0", "1", false}, 364 | {"1", "0", false}, 365 | // 2^32 - 1 == 2^32 - 1? 366 | {"ffffffff", "ffffffff", true}, 367 | // 2^64 - 1 == 2^64 - 2? 368 | {"ffffffffffffffff", "fffffffffffffffe", false}, 369 | // 0 == prime (mod prime)? 370 | {"0", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", true}, 371 | // 1 == prime+1 (mod prime)? 372 | {"1", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", true}, 373 | } 374 | 375 | t.Logf("Running %d tests", len(tests)) 376 | for i, test := range tests { 377 | f := new(fieldVal).SetHex(test.in1).Normalize() 378 | f2 := new(fieldVal).SetHex(test.in2).Normalize() 379 | result := f.Equals(f2) 380 | if result != test.expected { 381 | t.Errorf("fieldVal.Equals #%d wrong result\n"+ 382 | "got: %v\nwant: %v", i, result, test.expected) 383 | continue 384 | } 385 | } 386 | } 387 | 388 | // TestNegate ensures that negating field values via Negate works as expected. 389 | func TestNegate(t *testing.T) { 390 | tests := []struct { 391 | in string // hex encoded value 392 | expected string // expected hex encoded value 393 | }{ 394 | // secp256k1 prime (aka 0) 395 | {"0", "0"}, 396 | {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", "0"}, 397 | {"0", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"}, 398 | // secp256k1 prime-1 399 | {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", "1"}, 400 | {"1", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e"}, 401 | // secp256k1 prime-2 402 | {"2", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2d"}, 403 | {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2d", "2"}, 404 | // Random sampling 405 | { 406 | "b3d9aac9c5e43910b4385b53c7e78c21d4cd5f8e683c633aed04c233efc2e120", 407 | "4c2655363a1bc6ef4bc7a4ac381873de2b32a07197c39cc512fb3dcb103d1b0f", 408 | }, 409 | { 410 | "f8a85984fee5a12a7c8dd08830d83423c937d77c379e4a958e447a25f407733f", 411 | "757a67b011a5ed583722f77cf27cbdc36c82883c861b56a71bb85d90bf888f0", 412 | }, 413 | { 414 | "45ee6142a7fda884211e93352ed6cb2807800e419533be723a9548823ece8312", 415 | "ba119ebd5802577bdee16ccad12934d7f87ff1be6acc418dc56ab77cc131791d", 416 | }, 417 | { 418 | "53c2a668f07e411a2e473e1c3b6dcb495dec1227af27673761d44afe5b43d22b", 419 | "ac3d59970f81bee5d1b8c1e3c49234b6a213edd850d898c89e2bb500a4bc2a04", 420 | }, 421 | } 422 | 423 | t.Logf("Running %d tests", len(tests)) 424 | for i, test := range tests { 425 | f := new(fieldVal).SetHex(test.in).Normalize() 426 | expected := new(fieldVal).SetHex(test.expected).Normalize() 427 | result := f.Negate(1).Normalize() 428 | if !result.Equals(expected) { 429 | t.Errorf("fieldVal.Negate #%d wrong result\n"+ 430 | "got: %v\nwant: %v", i, result, expected) 431 | continue 432 | } 433 | } 434 | } 435 | 436 | // TestAddInt ensures that adding an integer to field values via AddInt works as 437 | // expected. 438 | func TestAddInt(t *testing.T) { 439 | tests := []struct { 440 | in1 string // hex encoded value 441 | in2 uint // unsigned integer to add to the value above 442 | expected string // expected hex encoded value 443 | }{ 444 | {"0", 1, "1"}, 445 | {"1", 0, "1"}, 446 | {"1", 1, "2"}, 447 | // secp256k1 prime-1 + 1 448 | {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", 1, "0"}, 449 | // secp256k1 prime + 1 450 | {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", 1, "1"}, 451 | // Random samples. 452 | { 453 | "ff95ad9315aff04ab4af0ce673620c7145dc85d03bab5ba4b09ca2c4dec2d6c1", 454 | 0x10f, 455 | "ff95ad9315aff04ab4af0ce673620c7145dc85d03bab5ba4b09ca2c4dec2d7d0", 456 | }, 457 | { 458 | "44bdae6b772e7987941f1ba314e6a5b7804a4c12c00961b57d20f41deea9cecf", 459 | 0x2cf11d41, 460 | "44bdae6b772e7987941f1ba314e6a5b7804a4c12c00961b57d20f41e1b9aec10", 461 | }, 462 | { 463 | "88c3ecae67b591935fb1f6a9499c35315ffad766adca665c50b55f7105122c9c", 464 | 0x4829aa2d, 465 | "88c3ecae67b591935fb1f6a9499c35315ffad766adca665c50b55f714d3bd6c9", 466 | }, 467 | { 468 | "8523e9edf360ca32a95aae4e57fcde5a542b471d08a974d94ea0ee09a015e2a6", 469 | 0xa21265a5, 470 | "8523e9edf360ca32a95aae4e57fcde5a542b471d08a974d94ea0ee0a4228484b", 471 | }, 472 | } 473 | 474 | t.Logf("Running %d tests", len(tests)) 475 | for i, test := range tests { 476 | f := new(fieldVal).SetHex(test.in1).Normalize() 477 | expected := new(fieldVal).SetHex(test.expected).Normalize() 478 | result := f.AddInt(test.in2).Normalize() 479 | if !result.Equals(expected) { 480 | t.Errorf("fieldVal.AddInt #%d wrong result\n"+ 481 | "got: %v\nwant: %v", i, result, expected) 482 | continue 483 | } 484 | } 485 | } 486 | 487 | // TestAdd ensures that adding two field values together via Add works as 488 | // expected. 489 | func TestAdd(t *testing.T) { 490 | tests := []struct { 491 | in1 string // first hex encoded value 492 | in2 string // second hex encoded value to add 493 | expected string // expected hex encoded value 494 | }{ 495 | {"0", "1", "1"}, 496 | {"1", "0", "1"}, 497 | {"1", "1", "2"}, 498 | // secp256k1 prime-1 + 1 499 | {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", "1", "0"}, 500 | // secp256k1 prime + 1 501 | {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", "1", "1"}, 502 | // Random samples. 503 | { 504 | "2b2012f975404e5065b4292fb8bed0a5d315eacf24c74d8b27e73bcc5430edcc", 505 | "2c3cefa4e4753e8aeec6ac4c12d99da4d78accefda3b7885d4c6bab46c86db92", 506 | "575d029e59b58cdb547ad57bcb986e4aaaa0b7beff02c610fcadf680c0b7c95e", 507 | }, 508 | { 509 | "8131e8722fe59bb189692b96c9f38de92885730f1dd39ab025daffb94c97f79c", 510 | "ff5454b765f0aab5f0977dcc629becc84cabeb9def48e79c6aadb2622c490fa9", 511 | "80863d2995d646677a00a9632c8f7ab175315ead0d1c824c9088b21c78e10b16", 512 | }, 513 | { 514 | "c7c95e93d0892b2b2cdd77e80eb646ea61be7a30ac7e097e9f843af73fad5c22", 515 | "3afe6f91a74dfc1c7f15c34907ee981656c37236d946767dd53ccad9190e437c", 516 | "02c7ce2577d72747abf33b3116a4df00b881ec6785c47ffc74c105d158bba36f", 517 | }, 518 | { 519 | "fd1c26f6a23381e5d785ba889494ec059369b888ad8431cd67d8c934b580dbe1", 520 | "a475aa5a31dcca90ef5b53c097d9133d6b7117474b41e7877bb199590fc0489c", 521 | "a191d150d4104c76c6e10e492c6dff42fedacfcff8c61954e38a628ec541284e", 522 | }, 523 | } 524 | 525 | t.Logf("Running %d tests", len(tests)) 526 | for i, test := range tests { 527 | f := new(fieldVal).SetHex(test.in1).Normalize() 528 | f2 := new(fieldVal).SetHex(test.in2).Normalize() 529 | expected := new(fieldVal).SetHex(test.expected).Normalize() 530 | result := f.Add(f2).Normalize() 531 | if !result.Equals(expected) { 532 | t.Errorf("fieldVal.Add #%d wrong result\n"+ 533 | "got: %v\nwant: %v", i, result, expected) 534 | continue 535 | } 536 | } 537 | } 538 | 539 | // TestAdd2 ensures that adding two field values together via Add2 works as 540 | // expected. 541 | func TestAdd2(t *testing.T) { 542 | tests := []struct { 543 | in1 string // first hex encoded value 544 | in2 string // second hex encoded value to add 545 | expected string // expected hex encoded value 546 | }{ 547 | {"0", "1", "1"}, 548 | {"1", "0", "1"}, 549 | {"1", "1", "2"}, 550 | // secp256k1 prime-1 + 1 551 | {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", "1", "0"}, 552 | // secp256k1 prime + 1 553 | {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", "1", "1"}, 554 | // close but over the secp256k1 prime 555 | {"fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000", "f1ffff000", "1ffff3d1"}, 556 | // Random samples. 557 | { 558 | "ad82b8d1cc136e23e9fd77fe2c7db1fe5a2ecbfcbde59ab3529758334f862d28", 559 | "4d6a4e95d6d61f4f46b528bebe152d408fd741157a28f415639347a84f6f574b", 560 | "faed0767a2e98d7330b2a0bcea92df3eea060d12380e8ec8b62a9fdb9ef58473", 561 | }, 562 | { 563 | "f3f43a2540054a86e1df98547ec1c0e157b193e5350fb4a3c3ea214b228ac5e7", 564 | "25706572592690ea3ddc951a1b48b504a4c83dc253756e1b96d56fdfb3199522", 565 | "19649f97992bdb711fbc2d6e9a0a75e5fc79d1a7888522bf5abf912bd5a45eda", 566 | }, 567 | { 568 | "6915bb94eef13ff1bb9b2633d997e13b9b1157c713363cc0e891416d6734f5b8", 569 | "11f90d6ac6fe1c4e8900b1c85fb575c251ec31b9bc34b35ada0aea1c21eded22", 570 | "7b0ec8ffb5ef5c40449bd7fc394d56fdecfd8980cf6af01bc29c2b898922e2da", 571 | }, 572 | { 573 | "48b0c9eae622eed9335b747968544eb3e75cb2dc8128388f948aa30f88cabde4", 574 | "0989882b52f85f9d524a3a3061a0e01f46d597839d2ba637320f4b9510c8d2d5", 575 | "523a5216391b4e7685a5aea9c9f52ed32e324a601e53dec6c699eea4999390b9", 576 | }, 577 | } 578 | 579 | t.Logf("Running %d tests", len(tests)) 580 | for i, test := range tests { 581 | f := new(fieldVal).SetHex(test.in1).Normalize() 582 | f2 := new(fieldVal).SetHex(test.in2).Normalize() 583 | expected := new(fieldVal).SetHex(test.expected).Normalize() 584 | result := f.Add2(f, f2).Normalize() 585 | if !result.Equals(expected) { 586 | t.Errorf("fieldVal.Add2 #%d wrong result\n"+ 587 | "got: %v\nwant: %v", i, result, expected) 588 | continue 589 | } 590 | } 591 | } 592 | 593 | // TestMulInt ensures that adding an integer to field values via MulInt works as 594 | // expected. 595 | func TestMulInt(t *testing.T) { 596 | tests := []struct { 597 | in1 string // hex encoded value 598 | in2 uint // unsigned integer to multiply with value above 599 | expected string // expected hex encoded value 600 | }{ 601 | {"0", 0, "0"}, 602 | {"1", 0, "0"}, 603 | {"0", 1, "0"}, 604 | {"1", 1, "1"}, 605 | // secp256k1 prime-1 * 2 606 | { 607 | "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", 608 | 2, 609 | "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2d", 610 | }, 611 | // secp256k1 prime * 3 612 | {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", 3, "0"}, 613 | // secp256k1 prime-1 * 8 614 | { 615 | "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", 616 | 8, 617 | "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc27", 618 | }, 619 | // Random samples for first value. The second value is limited 620 | // to 8 since that is the maximum int used in the elliptic curve 621 | // calculations. 622 | { 623 | "b75674dc9180d306c692163ac5e089f7cef166af99645c0c23568ab6d967288a", 624 | 6, 625 | "4c06bd2b6904f228a76c8560a3433bced9a8681d985a2848d407404d186b0280", 626 | }, 627 | { 628 | "54873298ac2b5ba8591c125ae54931f5ea72040aee07b208d6135476fb5b9c0e", 629 | 3, 630 | "fd9597ca048212f90b543710afdb95e1bf560c20ca17161a8239fd64f212d42a", 631 | }, 632 | { 633 | "7c30fbd363a74c17e1198f56b090b59bbb6c8755a74927a6cba7a54843506401", 634 | 5, 635 | "6cf4eb20f2447c77657fccb172d38c0aa91ea4ac446dc641fa463a6b5091fba7", 636 | }, 637 | { 638 | "fb4529be3e027a3d1587d8a500b72f2d312e3577340ef5175f96d113be4c2ceb", 639 | 8, 640 | "da294df1f013d1e8ac3ec52805b979698971abb9a077a8bafcb688a4f261820f", 641 | }, 642 | } 643 | 644 | t.Logf("Running %d tests", len(tests)) 645 | for i, test := range tests { 646 | f := new(fieldVal).SetHex(test.in1).Normalize() 647 | expected := new(fieldVal).SetHex(test.expected).Normalize() 648 | result := f.MulInt(test.in2).Normalize() 649 | if !result.Equals(expected) { 650 | t.Errorf("fieldVal.MulInt #%d wrong result\n"+ 651 | "got: %v\nwant: %v", i, result, expected) 652 | continue 653 | } 654 | } 655 | } 656 | 657 | // TestMul ensures that multiplying two field valuess via Mul works as expected. 658 | func TestMul(t *testing.T) { 659 | tests := []struct { 660 | in1 string // first hex encoded value 661 | in2 string // second hex encoded value to multiply with 662 | expected string // expected hex encoded value 663 | }{ 664 | {"0", "0", "0"}, 665 | {"1", "0", "0"}, 666 | {"0", "1", "0"}, 667 | {"1", "1", "1"}, 668 | // slightly over prime 669 | { 670 | "ffffffffffffffffffffffffffffffffffffffffffffffffffffffff1ffff", 671 | "1000", 672 | "1ffff3d1", 673 | }, 674 | // secp256k1 prime-1 * 2 675 | { 676 | "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", 677 | "2", 678 | "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2d", 679 | }, 680 | // secp256k1 prime * 3 681 | {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", "3", "0"}, 682 | // secp256k1 prime-1 * 8 683 | { 684 | "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", 685 | "8", 686 | "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc27", 687 | }, 688 | // Random samples. 689 | { 690 | "cfb81753d5ef499a98ecc04c62cb7768c2e4f1740032946db1c12e405248137e", 691 | "58f355ad27b4d75fb7db0442452e732c436c1f7c5a7c4e214fa9cc031426a7d3", 692 | "1018cd2d7c2535235b71e18db9cd98027386328d2fa6a14b36ec663c4c87282b", 693 | }, 694 | { 695 | "26e9d61d1cdf3920e9928e85fa3df3e7556ef9ab1d14ec56d8b4fc8ed37235bf", 696 | "2dfc4bbe537afee979c644f8c97b31e58be5296d6dbc460091eae630c98511cf", 697 | "da85f48da2dc371e223a1ae63bd30b7e7ee45ae9b189ac43ff357e9ef8cf107a", 698 | }, 699 | { 700 | "5db64ed5afb71646c8b231585d5b2bf7e628590154e0854c4c29920b999ff351", 701 | "279cfae5eea5d09ade8e6a7409182f9de40981bc31c84c3d3dfe1d933f152e9a", 702 | "2c78fbae91792dd0b157abe3054920049b1879a7cc9d98cfda927d83be411b37", 703 | }, 704 | { 705 | "b66dfc1f96820b07d2bdbd559c19319a3a73c97ceb7b3d662f4fe75ecb6819e6", 706 | "bf774aba43e3e49eb63a6e18037d1118152568f1a3ac4ec8b89aeb6ff8008ae1", 707 | "c4f016558ca8e950c21c3f7fc15f640293a979c7b01754ee7f8b3340d4902ebb", 708 | }, 709 | } 710 | 711 | t.Logf("Running %d tests", len(tests)) 712 | for i, test := range tests { 713 | f := new(fieldVal).SetHex(test.in1).Normalize() 714 | f2 := new(fieldVal).SetHex(test.in2).Normalize() 715 | expected := new(fieldVal).SetHex(test.expected).Normalize() 716 | result := f.Mul(f2).Normalize() 717 | if !result.Equals(expected) { 718 | t.Errorf("fieldVal.Mul #%d wrong result\n"+ 719 | "got: %v\nwant: %v", i, result, expected) 720 | continue 721 | } 722 | } 723 | } 724 | 725 | // TestSquare ensures that squaring field values via Square works as expected. 726 | func TestSquare(t *testing.T) { 727 | tests := []struct { 728 | in string // hex encoded value 729 | expected string // expected hex encoded value 730 | }{ 731 | // secp256k1 prime (aka 0) 732 | {"0", "0"}, 733 | {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", "0"}, 734 | {"0", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"}, 735 | // secp256k1 prime-1 736 | {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", "1"}, 737 | // secp256k1 prime-2 738 | {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2d", "4"}, 739 | // Random sampling 740 | { 741 | "b0ba920360ea8436a216128047aab9766d8faf468895eb5090fc8241ec758896", 742 | "133896b0b69fda8ce9f648b9a3af38f345290c9eea3cbd35bafcadf7c34653d3", 743 | }, 744 | { 745 | "c55d0d730b1d0285a1599995938b042a756e6e8857d390165ffab480af61cbd5", 746 | "cd81758b3f5877cbe7e5b0a10cebfa73bcbf0957ca6453e63ee8954ab7780bee", 747 | }, 748 | { 749 | "e89c1f9a70d93651a1ba4bca5b78658f00de65a66014a25544d3365b0ab82324", 750 | "39ffc7a43e5dbef78fd5d0354fb82c6d34f5a08735e34df29da14665b43aa1f", 751 | }, 752 | { 753 | "7dc26186079d22bcbe1614aa20ae627e62d72f9be7ad1e99cac0feb438956f05", 754 | "bf86bcfc4edb3d81f916853adfda80c07c57745b008b60f560b1912f95bce8ae", 755 | }, 756 | } 757 | 758 | t.Logf("Running %d tests", len(tests)) 759 | for i, test := range tests { 760 | f := new(fieldVal).SetHex(test.in).Normalize() 761 | expected := new(fieldVal).SetHex(test.expected).Normalize() 762 | result := f.Square().Normalize() 763 | if !result.Equals(expected) { 764 | t.Errorf("fieldVal.Square #%d wrong result\n"+ 765 | "got: %v\nwant: %v", i, result, expected) 766 | continue 767 | } 768 | } 769 | } 770 | 771 | // TestInverse ensures that finding the multiplicative inverse via Inverse works 772 | // as expected. 773 | func TestInverse(t *testing.T) { 774 | tests := []struct { 775 | in string // hex encoded value 776 | expected string // expected hex encoded value 777 | }{ 778 | // secp256k1 prime (aka 0) 779 | {"0", "0"}, 780 | {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", "0"}, 781 | {"0", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"}, 782 | // secp256k1 prime-1 783 | { 784 | "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", 785 | "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", 786 | }, 787 | // secp256k1 prime-2 788 | { 789 | "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2d", 790 | "7fffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffffe17", 791 | }, 792 | // Random sampling 793 | { 794 | "16fb970147a9acc73654d4be233cc48b875ce20a2122d24f073d29bd28805aca", 795 | "987aeb257b063df0c6d1334051c47092b6d8766c4bf10c463786d93f5bc54354", 796 | }, 797 | { 798 | "69d1323ce9f1f7b3bd3c7320b0d6311408e30281e273e39a0d8c7ee1c8257919", 799 | "49340981fa9b8d3dad72de470b34f547ed9179c3953797d0943af67806f4bb6", 800 | }, 801 | { 802 | "e0debf988ae098ecda07d0b57713e97c6d213db19753e8c95aa12a2fc1cc5272", 803 | "64f58077b68af5b656b413ea366863f7b2819f8d27375d9c4d9804135ca220c2", 804 | }, 805 | { 806 | "dcd394f91f74c2ba16aad74a22bb0ed47fe857774b8f2d6c09e28bfb14642878", 807 | "fb848ec64d0be572a63c38fe83df5e7f3d032f60bf8c969ef67d36bf4ada22a9", 808 | }, 809 | } 810 | 811 | t.Logf("Running %d tests", len(tests)) 812 | for i, test := range tests { 813 | f := new(fieldVal).SetHex(test.in).Normalize() 814 | expected := new(fieldVal).SetHex(test.expected).Normalize() 815 | result := f.Inverse().Normalize() 816 | if !result.Equals(expected) { 817 | t.Errorf("fieldVal.Inverse #%d wrong result\n"+ 818 | "got: %v\nwant: %v", i, result, expected) 819 | continue 820 | } 821 | } 822 | } 823 | --------------------------------------------------------------------------------