github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/crypto/key.go (about)

     1  // Copyright 2017-2018 DERO Project. All rights reserved.
     2  // Use of this source code in any form is governed by RESEARCH license.
     3  // license can be found in the LICENSE file.
     4  // GPG: 0F39 E425 8C65 3947 702A  8234 08B2 0360 A03A 9DE8
     5  //
     6  //
     7  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
     8  // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     9  // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
    10  // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    11  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    12  // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    13  // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    14  // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
    15  // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    16  
    17  package crypto
    18  
    19  import "io"
    20  import "fmt"
    21  import "bytes"
    22  import "crypto/rand"
    23  import "encoding/hex"
    24  import "encoding/binary"
    25  
    26  const KeyLength = 32
    27  
    28  // Key can be a Scalar or a Point
    29  type Key [KeyLength]byte
    30  
    31  func (k Key) MarshalText() ([]byte, error) {
    32  	return []byte(fmt.Sprintf("%x", k[:])), nil
    33  }
    34  
    35  func (k *Key) UnmarshalText(data []byte) (err error) {
    36  	byteSlice, _ := hex.DecodeString(string(data))
    37  	if len(byteSlice) != 32 {
    38  		return fmt.Errorf("Incorrect key size")
    39  	}
    40  	copy(k[:], byteSlice)
    41  	return
    42  }
    43  
    44  func (k Key) String() string {
    45  	return fmt.Sprintf("%x", k[:])
    46  }
    47  
    48  func (p *Key) FromBytes(b [KeyLength]byte) {
    49  	*p = b
    50  }
    51  
    52  func (p *Key) ToBytes() (result [KeyLength]byte) {
    53  	result = [KeyLength]byte(*p)
    54  	return
    55  }
    56  
    57  // convert a hex string to a key
    58  func HexToKey(h string) (result Key) {
    59  	byteSlice, _ := hex.DecodeString(h)
    60  	if len(byteSlice) != 32 {
    61  		panic("Incorrect key size")
    62  	}
    63  	copy(result[:], byteSlice)
    64  	return
    65  }
    66  
    67  func HexToHash(h string) (result Hash) {
    68  	byteSlice, _ := hex.DecodeString(h)
    69  	if len(byteSlice) != 32 {
    70  		panic("Incorrect key size")
    71  	}
    72  	copy(result[:], byteSlice)
    73  	return
    74  }
    75  
    76  // generates a public from the secret key
    77  func (p *Key) PublicKey() (pubKey *Key) {
    78  	point := new(ExtendedGroupElement)
    79  	GeScalarMultBase(point, p)
    80  	pubKey = new(Key)
    81  	point.ToBytes(pubKey)
    82  	return
    83  }
    84  
    85  // tests whether the key is valid ( represents a point on the curve )
    86  // this is equivalent to bool crypto_ops::check_key(const public_key &key)
    87  func (k *Key) Public_Key_Valid() bool {
    88  	var point ExtendedGroupElement
    89  	return point.FromBytes(k)
    90  }
    91  
    92  func (k *Key) Private_Key_Valid() bool {
    93  	return Sc_check(k)
    94  }
    95  
    96  // Creates a point on the Edwards Curve by hashing the key
    97  func (p *Key) HashToEC() (result *ExtendedGroupElement) {
    98  	result = new(ExtendedGroupElement)
    99  	var p1 ProjectiveGroupElement
   100  	var p2 CompletedGroupElement
   101  	h := Key(Keccak256(p[:]))
   102  	p1.FromBytes(&h)
   103  
   104  	// fmt.Printf("p1 %+v\n", p1)
   105  	GeMul8(&p2, &p1)
   106  	p2.ToExtended(result)
   107  	return
   108  }
   109  
   110  func (p *Key) HashToPoint() (result Key) {
   111  	extended := p.HashToEC()
   112  	extended.ToBytes(&result)
   113  	return
   114  }
   115  
   116  // compatible with hashToPointSimple
   117  // NOTE: this is incompatible with HashToPoint ( though it should have been)
   118  // there are no side-effects or degradtion of crypto, due to this
   119  // however, the mistakes have to kept as they were in original code base
   120  // this function is only used to generate H from G
   121  func (p *Key) HashToPointSimple() (result Key) {
   122  	h := Key(Keccak256(p[:]))
   123  	extended := new(ExtendedGroupElement)
   124  	extended.FromBytes(&h)
   125  
   126  	// convert extended to projective
   127  	var p1 ProjectiveGroupElement
   128  
   129  	extended.ToProjective(&p1)
   130  	var p2 CompletedGroupElement
   131  
   132  	GeMul8(&p2, &p1)
   133  	p2.ToExtended(extended)
   134  	extended.ToBytes(&result)
   135  	return
   136  }
   137  
   138  // this uses random number generator from the OS
   139  func RandomScalar() (result *Key) {
   140  	result = new(Key)
   141  	var reduceFrom [KeyLength * 2]byte
   142  	tmp := make([]byte, KeyLength*2)
   143  	rand.Read(tmp)
   144  	copy(reduceFrom[:], tmp)
   145  	ScReduce(result, &reduceFrom)
   146  	return
   147  }
   148  
   149  // generate a new private-public key pair
   150  func NewKeyPair() (privKey *Key, pubKey *Key) {
   151  	privKey = RandomScalar()
   152  	pubKey = privKey.PublicKey()
   153  	return
   154  }
   155  
   156  func ParseKey(buf io.Reader) (result Key, err error) {
   157  	key := make([]byte, KeyLength)
   158  	if _, err = buf.Read(key); err != nil {
   159  		return
   160  	}
   161  	copy(result[:], key)
   162  	return
   163  }
   164  
   165  /*
   166     //does a * G where a is a scalar and G is the curve basepoint
   167      key scalarmultBase(const key & a) {
   168          ge_p3 point;
   169          key aG;
   170          sc_reduce32copy(aG.bytes, a.bytes); //do this beforehand
   171          ge_scalarmult_base(&point, aG.bytes);
   172          ge_p3_tobytes(aG.bytes, &point);
   173          return aG;
   174      }
   175  */
   176  //does a * G where a is a scalar and G is the curve basepoint
   177  
   178  func ScalarmultBase(a Key) (aG Key) {
   179  	reduce32copy := a
   180  	ScReduce32(&reduce32copy)
   181  	point := new(ExtendedGroupElement)
   182  	GeScalarMultBase(point, &a)
   183  	point.ToBytes(&aG)
   184  	return aG
   185  }
   186  
   187  // generates a key which can be used as private key or mask
   188  // this function is similiar to  RandomScalar except for reduce32, TODO can we merge both
   189  func skGen() Key {
   190  	skey := RandomScalar()
   191  	ScReduce32(skey)
   192  	return *skey
   193  }
   194  func SkGen() Key {
   195  	return skGen()
   196  }
   197  
   198  func (k *Key) ToExtended() (result *ExtendedGroupElement) {
   199  	result = new(ExtendedGroupElement)
   200  	result.FromBytes(k)
   201  	return
   202  }
   203  
   204  // bothe the function resturn identity of the ed25519 curve
   205  func identity() (result *Key) {
   206  	result = new(Key)
   207  	result[0] = 1
   208  	return
   209  }
   210  
   211  func CurveIdentity() (result Key) {
   212  	result = Identity
   213  	return result
   214  }
   215  
   216  func CurveOrder() (result Key) {
   217  	result = L
   218  	return result
   219  }
   220  
   221  // convert a uint64 to a scalar
   222  func d2h(val uint64) (result *Key) {
   223  	result = new(Key)
   224  	for i := 0; val > 0; i++ {
   225  		result[i] = byte(val & 0xFF)
   226  		val /= 256
   227  	}
   228  	return
   229  }
   230  
   231  func HashToScalar(data ...[]byte) (result *Key) {
   232  	result = new(Key)
   233  	*result = Key(Keccak256(data...))
   234  	ScReduce32(result)
   235  	return
   236  }
   237  
   238  // does a * P where a is a scalar and P is an arbitrary point
   239  func ScalarMultKey(Point *Key, scalar *Key) (result *Key) {
   240  	var P ExtendedGroupElement
   241  	P.FromBytes(Point)
   242  	var resultPoint ProjectiveGroupElement
   243  	GeScalarMult(&resultPoint, scalar, &P)
   244  	result = new(Key)
   245  	resultPoint.ToBytes(result)
   246  	return
   247  }
   248  
   249  // multiply a scalar by H (second curve point of Pedersen Commitment)
   250  func ScalarMultH(scalar *Key) (result *Key) {
   251  	h := new(ExtendedGroupElement)
   252  	h.FromBytes(&H)
   253  	resultPoint := new(ProjectiveGroupElement)
   254  	GeScalarMult(resultPoint, scalar, h)
   255  	result = new(Key)
   256  	resultPoint.ToBytes(result)
   257  	return
   258  }
   259  
   260  // add two points together
   261  func AddKeys(sum, k1, k2 *Key) {
   262  	a := k1.ToExtended()
   263  	var b CachedGroupElement
   264  	k2.ToExtended().ToCached(&b)
   265  	var c CompletedGroupElement
   266  	geAdd(&c, a, &b)
   267  	var tmp ExtendedGroupElement
   268  	c.ToExtended(&tmp)
   269  	tmp.ToBytes(sum)
   270  	return
   271  }
   272  
   273  // compute a*G + b*B
   274  func AddKeys2(result, a, b, B *Key) {
   275  	BPoint := B.ToExtended()
   276  	var RPoint ProjectiveGroupElement
   277  	GeDoubleScalarMultVartime(&RPoint, b, BPoint, a)
   278  	RPoint.ToBytes(result)
   279  	return
   280  }
   281  
   282  //addKeys3
   283  //aAbB = a*A + b*B where a, b are scalars, A, B are curve points
   284  //B must be input after applying "precomp"
   285  func AddKeys3(result *Key, a *Key, A *Key, b *Key, B_Precomputed *[8]CachedGroupElement) {
   286  	var A_Point ExtendedGroupElement
   287  	A_Point.FromBytes(A)
   288  
   289  	var result_projective ProjectiveGroupElement
   290  	GeDoubleScalarMultPrecompVartime(&result_projective, a, &A_Point, b, B_Precomputed)
   291  	result_projective.ToBytes(result)
   292  
   293  }
   294  
   295  //addKeys3_3  this is similiar to addkeys3 except it allows for use of precomputed A,B
   296  //aAbB = a*A + b*B where a, b are scalars, A, B are curve points
   297  //A,B must be input after applying "precomp"
   298  func AddKeys3_3(result *Key, a *Key, A_Precomputed *[8]CachedGroupElement, b *Key, B_Precomputed *[8]CachedGroupElement) {
   299  	var result_projective ProjectiveGroupElement
   300  	GeDoubleScalarMultPrecompVartime2(&result_projective, a, A_Precomputed, b, B_Precomputed)
   301  	result_projective.ToBytes(result)
   302  
   303  }
   304  
   305  // subtract two points A - B
   306  func SubKeys(diff, k1, k2 *Key) {
   307  	a := k1.ToExtended()
   308  	b := new(CachedGroupElement)
   309  	k2.ToExtended().ToCached(b)
   310  	c := new(CompletedGroupElement)
   311  	geSub(c, a, b)
   312  	tmp := new(ExtendedGroupElement)
   313  	c.ToExtended(tmp)
   314  	tmp.ToBytes(diff)
   315  	return
   316  }
   317  
   318  // zero fill the key
   319  func Sc_0(k *Key) {
   320  	for i := 0; i < 32; i++ {
   321  		k[i] = 0
   322  	}
   323  }
   324  
   325  // RandomPubKey takes a random scalar, interprets it as a point on the curve
   326  //  remember the low order bug and do more auditing of the entire thing
   327  func RandomPubKey() (result *Key) {
   328  	result = new(Key)
   329  	p3 := new(ExtendedGroupElement)
   330  	var p1 ProjectiveGroupElement
   331  	var p2 CompletedGroupElement
   332  	h := RandomScalar()
   333  	p1.FromBytes(h)
   334  	GeMul8(&p2, &p1)
   335  	p2.ToExtended(p3)
   336  	p3.ToBytes(result)
   337  	return
   338  }
   339  
   340  // this is the main key derivation function and is the crux
   341  // when deriving keys in the case user  A wants to send DERO to another user B ( this is outgoing case)
   342  // public key is B's view key
   343  // private keys is TX private key
   344  // if user B wants to derive key, he needs to   ( this is incoming case )
   345  // public key is TX public key
   346  // private is B's private keys
   347  // HOPE the above is  clean and clear
   348  
   349  func KeyDerivation(pub *Key, priv *Key) (KeyDerivation Key) {
   350  	var point ExtendedGroupElement
   351  	var point2 ProjectiveGroupElement
   352  	var point3 CompletedGroupElement
   353  
   354  	if !priv.Private_Key_Valid() {
   355  		panic("Invalid private key.")
   356  	}
   357  	tmp := *pub
   358  	if !point.FromBytes(&tmp) {
   359  		panic("Invalid public key.")
   360  	}
   361  
   362  	tmp = *priv
   363  	GeScalarMult(&point2, &tmp, &point)
   364  	GeMul8(&point3, &point2)
   365  	point3.ToProjective(&point2)
   366  
   367  	point2.ToBytes(&tmp)
   368  	return tmp
   369  }
   370  
   371  // the origincal c implementation needs to be checked for varint overflow
   372  // we also need to check the compatibility of golang varint with cryptonote implemented varint
   373  // outputIndex is the position of output within that specific transaction
   374  func (k *Key) KeyDerivationToScalar(outputIndex uint64) (scalar *Key) {
   375  	tmp := make([]byte, 12, 12)
   376  
   377  	length := binary.PutUvarint(tmp, outputIndex)
   378  	tmp = tmp[:length]
   379  
   380  	var buf bytes.Buffer
   381  	buf.Write(k[:])
   382  	buf.Write(tmp)
   383  	scalar = HashToScalar(buf.Bytes())
   384  	return
   385  }
   386  
   387  // generate ephermal keys  from a key derivation
   388  // base key is the B's public spend key or A's private spend key
   389  // outputIndex is the position of output within that specific transaction
   390  func (kd *Key) KeyDerivation_To_PublicKey(outputIndex uint64, baseKey Key) Key {
   391  
   392  	var point1, point2 ExtendedGroupElement
   393  	var point3 CachedGroupElement
   394  	var point4 CompletedGroupElement
   395  	var point5 ProjectiveGroupElement
   396  
   397  	tmp := baseKey
   398  	if !point1.FromBytes(&tmp) {
   399  		panic("Invalid public key.")
   400  	}
   401  	scalar := kd.KeyDerivationToScalar(outputIndex)
   402  	GeScalarMultBase(&point2, scalar)
   403  	point2.ToCached(&point3)
   404  	geAdd(&point4, &point1, &point3)
   405  	point4.ToProjective(&point5)
   406  	point5.ToBytes(&tmp)
   407  	return tmp
   408  }
   409  
   410  // generate ephermal keys  from a key derivation
   411  // base key is the A's private spend key
   412  // outputIndex is the position of output within that specific transaction
   413  func (kd *Key) KeyDerivation_To_PrivateKey(outputIndex uint64, baseKey Key) Key {
   414  	if !baseKey.Private_Key_Valid() {
   415  		panic("Invalid private key.")
   416  	}
   417  	scalar := kd.KeyDerivationToScalar(outputIndex)
   418  
   419  	tmp := baseKey
   420  	ScAdd(&tmp, &tmp, scalar)
   421  	return tmp
   422  }
   423  
   424  // NewKeyImage creates a new KeyImage from the given public and private keys.
   425  // The keys are usually the ephemeral keys derived using KeyDerivation.
   426  func GenerateKeyImage(pub Key, private Key) Key {
   427  	var proj ProjectiveGroupElement
   428  
   429  	ext := pub.HashToEC()
   430  	GeScalarMult(&proj, &private, ext)
   431  
   432  	var ki Key
   433  	proj.ToBytes(&ki)
   434  	return ki
   435  }