github.com/klaytn/klaytn@v1.12.1/crypto/secp256k1/schnorr.go (about)

     1  // Copyright 2018 The klaytn Authors
     2  //
     3  // This file is part of the klaytn library.
     4  //
     5  // The klaytn library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The klaytn library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the klaytn library. If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package secp256k1
    19  
    20  import (
    21  	"bytes"
    22  	"crypto/sha256"
    23  	"sort"
    24  )
    25  
    26  // SchnorrSignSingle digitally signs the input message using Schnorr signature scheme.
    27  func SchnorrSignSingle(G *BitCurve, msg, x, P []byte) ([]byte, []byte) {
    28  	// [Schnorr Signature 101]
    29  	//
    30  	// 1) Deriving public key from private key
    31  	// : P = x * G
    32  	// : P is a corresponding public key
    33  	// : x is a private key
    34  	// : G is a curve base point
    35  	//
    36  	// 2) Creating a random scalar for signing
    37  	// : k = H(m || x)
    38  	//
    39  	// 3) Compute the first part of Schnorr signature, R
    40  	// : R = k * G
    41  	//
    42  	// The goal is to make R = s * G + e * P for some s and e.
    43  	//
    44  	// 4) Compute e
    45  	// : e = H(m || P || R)
    46  	//
    47  	// 5) Find s
    48  	// Recall P = x * G; therefore
    49  	// R     = s * G + e * P
    50  	//       = s * G + e * x * G
    51  	//       = (s + e * x) * G
    52  	// k * G = (s + e * x) * G
    53  	// k     = s + e * x
    54  	// s     = k - e * x
    55  	//
    56  	// Finally, (R, s) is your Schnorr signature
    57  
    58  	k := hash(msg, x)                   // k = H(m || x)
    59  	R := G.Marshal(G.ScalarBaseMult(k)) // R = k * G
    60  
    61  	e := hash(msg, P, R) // e = H(m || P || R)
    62  
    63  	ex := ScMul(e, x) // e * x
    64  	s := ScSub(k, ex) // s = k - e * x
    65  
    66  	return R, s
    67  }
    68  
    69  // SchnorrVerifySingle verifies a Schnorr signature.
    70  // Note that this implementation is relatively slow compared to the C implementation. Use this sparingly.
    71  func SchnorrVerify(G *BitCurve, msg, R, s, P []byte) bool {
    72  	e := hash(msg, P, R)
    73  
    74  	sx, sy := G.ScalarBaseMult(s)
    75  
    76  	Px, Py := G.Unmarshal(P)
    77  	ePx, ePy := G.ScalarMult(Px, Py, e)
    78  
    79  	V := G.Marshal(G.Add(sx, sy, ePx, ePy))
    80  
    81  	return bytes.Equal(R, V) // R == s*G + e*P
    82  }
    83  
    84  /*
    85  	[Brief Overview on Schnorr 2-out-of-2 signature scheme]
    86  
    87  	In Schnorr signature, Alice shares (R, s) with R = k * G
    88  	where k is an arbitrary number and G is an elliptic curve group.
    89  
    90  	R can be computed from (e, s) via R = s * G + e * P for some e ans s and
    91  	e can be computed from (R, s) via e = H(m || P || R)
    92  
    93  	To sign a message, Alice needs to pick a value for k. For security reason,
    94  	k should not be reused over multiple messages.
    95  
    96  	Given a message m and private key x, we use k = H(m || x) where H is a secure hash function.
    97  
    98  	R	=	k * G
    99  		=	H(m || x) * G
   100  
   101  	Recall that R = s * G + e * P. Hence,
   102  
   103  	R	=	s * G + e * P      = k * G
   104  			s * G + e * x * G  = k * G
   105  			(s + e * x) * G    = k * G
   106  			s + e * x          = k             (*)
   107  
   108  	By (*), s = k - e * x                      (**)
   109  
   110  	Suppose Alice and Bob have the following keys:
   111  
   112  	Alice:	P0 = x0 * G
   113  	Bob:	P1 = x1 * G
   114  
   115  	Alice and Bob can safely create a multisig on a message, m, by using generated keys.
   116  
   117  	1. 	C = H(P0 || P1)         Let C be the common value that both Alice and Bob use to generate safe keys
   118  
   119  	2. 	Q0 = H(C || P0) * P0    Let Q0 be Alice's public key
   120  	3. 	Q1 = H(C || P1) * P1    Let Q1 be Bob's public key
   121  	4. 	P = Q0 + Q1             Let P be the public key for the target multisig
   122  
   123  	5. 	y0 = x0 * H(C || P0)    Let y0 be Alice's private key
   124  	6. 	y1 = x1 * H(C || P1)    Let y1 be Bob's private key
   125  
   126  	7. 	k0 = H(m || y0)         Alice's random value for m
   127  	8. 	k1 = H(m || y1)         Bob's random value for m
   128  	9. 	R0 = k0 * G
   129  	10.	R1 = k1 * G
   130  	11.	R = R0 + R1
   131  
   132  	We use e = H(m || P || R) to harden the security, preventing either Alice or Bob from stealing
   133  	the control over the other party's key.
   134  
   135  	Assuming Alice and Bob have already exchanged Q0, Q1, R0 and R1, Alice and Bob can compute the followings:
   136  
   137  	e = H(m || P || R)										by (4),  (11)
   138  
   139  	Using the computed e, Alice and Bob can compute s0 and s1.
   140  
   141  	Alice:   s0 = k0 - e * y0
   142  	Bob:     s1 = k1 - e * y1
   143  
   144  	Once they exchange s0 and s1, they can compute s.
   145  
   146  	s = s0 + s1
   147  
   148  	Thus, Alice and Bob can publish (R, s) as a signature for m.
   149  	Verifying (R, s) can be done by computing R = s * G + H(m || P || R) * P.
   150  */
   151  
   152  // ComputeC derives the common value for multiple public keys.
   153  func ComputeC(keys ...[]byte) []byte {
   154  	sort.SliceStable(keys, func(i, j int) bool {
   155  		return bytes.Compare(keys[i], keys[j]) < 0
   156  	})
   157  	return hash(keys...)
   158  }
   159  
   160  // SchnorrSignMultiBootstrap computes an individual share of a Schnorr multi-signature given all public keys.
   161  // Q: a dedicated, security hardened public key for this multi-signature party
   162  // R: a part of the generating multi-signature for the input publickey
   163  // y: a dedicated, security hardened private key for this multi-signature party
   164  func SchnorrSignMultiBootstrap(G *BitCurve, msg, privateKey, publicKey []byte, othersPublicKeys ...[]byte) (Q, R, y []byte) {
   165  	C := ComputeC(append([][]byte{publicKey}, othersPublicKeys...)...)
   166  
   167  	z := hash(C, publicKey)
   168  
   169  	Px, Py := G.Unmarshal(publicKey)
   170  	Qx, Qy := G.ScalarMult(Px, Py, z)
   171  
   172  	y = ScMul(privateKey, z)
   173  
   174  	k := hash(msg, y)
   175  
   176  	Rx, Ry := G.ScalarBaseMult(k)
   177  
   178  	Q = G.Marshal(Qx, Qy)
   179  	R = G.Marshal(Rx, Ry)
   180  	return
   181  }
   182  
   183  // SchnorrSignMultiComputeS computes the s part of a Schnorr multi-signature (i.e., s in (R, s)).
   184  func SchnorrSignMultiComputeS(msg, P, R, y []byte) []byte {
   185  	e := hash(msg, P, R)
   186  	k := hash(msg, y)
   187  	return ScSub(k, ScMul(e, y))
   188  }
   189  
   190  // Simple helper function concatenating all input bytes and summing it up with SHA256.
   191  func hash(bytes ...[]byte) []byte {
   192  	h := sha256.New()
   193  	for _, b := range bytes {
   194  		h.Write(b)
   195  	}
   196  	result := h.Sum(nil)
   197  	return result[:]
   198  }