github.com/incognitochain/go-incognito-sdk@v1.0.1/privacy/curve25519/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 curve25519
    18  
    19  import (
    20  	"io"
    21  )
    22  import "fmt"
    23  import "bytes"
    24  import "crypto/rand"
    25  import "encoding/hex"
    26  import "encoding/binary"
    27  
    28  const KeyLength = 32
    29  
    30  // Key can be a Scalar or a Point
    31  type Key [KeyLength]byte
    32  
    33  func (k Key) MarshalText() ([]byte ) {
    34  	return []byte(fmt.Sprintf("%x", k[:]))
    35  }
    36  
    37  func (k *Key) UnmarshalText(data []byte) (err error) {
    38  	byteSlice, _ := hex.DecodeString(string(data))
    39  	if len(byteSlice) != 32 {
    40  		return fmt.Errorf("Incorrect key size")
    41  	}
    42  	copy(k[:], byteSlice)
    43  	return
    44  }
    45  
    46  func (k Key) String() string {
    47  	return fmt.Sprintf("%x", k[:])
    48  }
    49  
    50  func (p *Key) FromBytes(b [KeyLength]byte) {
    51  	*p = b
    52  }
    53  
    54  func (p *Key) ToBytes() (result [KeyLength]byte) {
    55  	result = [KeyLength]byte(*p)
    56  	return
    57  }
    58  
    59  // convert a hex string to a key
    60  func HexToKey(h string) (result Key) {
    61  	byteSlice, _ := hex.DecodeString(h)
    62  	if len(byteSlice) != 32 {
    63  		panic("Incorrect key size")
    64  	}
    65  	copy(result[:], byteSlice)
    66  	return
    67  }
    68  
    69  func HexToHash(h string) (result Hash) {
    70  	byteSlice, _ := hex.DecodeString(h)
    71  	if len(byteSlice) != 32 {
    72  		panic("Incorrect key size")
    73  	}
    74  	copy(result[:], byteSlice)
    75  	return
    76  }
    77  
    78  // generates a public from the secret key
    79  func (p *Key) PublicKey() (pubKey *Key) {
    80  	point := new(ExtendedGroupElement)
    81  	GeScalarMultBase(point, p)
    82  	pubKey = new(Key)
    83  	point.ToBytes(pubKey)
    84  	return
    85  }
    86  
    87  // tests whether the key is valid ( represents a point on the curve )
    88  // this is equivalent to bool crypto_ops::check_key(const public_key &key)
    89  func (k *Key) Public_Key_Valid() bool {
    90  	var point ExtendedGroupElement
    91  	return point.FromBytes(k)
    92  }
    93  
    94  func (k *Key) Private_Key_Valid() bool {
    95  	return Sc_check(k)
    96  }
    97  
    98  // Creates a point on the Edwards Curve by hashing the key
    99  func (p *Key) HashToEC() (result *ExtendedGroupElement) {
   100  	result = new(ExtendedGroupElement)
   101  	var p1 ProjectiveGroupElement
   102  	var p2 CompletedGroupElement
   103  	h := Key(Keccak256(p[:]))
   104  	p1.FromBytes(&h)
   105  
   106  	// fmt.Printf("p1 %+v\n", p1)
   107  	GeMul8(&p2, &p1)
   108  	p2.ToExtended(result)
   109  	return
   110  }
   111  
   112  func (p *Key) HashToPoint() (result *Key) {
   113  	if result == nil {
   114  		result = new(Key)
   115  	}
   116  	extended := p.HashToEC()
   117  	extended.ToBytes(result)
   118  	return
   119  }
   120  
   121  // compatible with hashToPointSimple
   122  // NOTE: this is incompatible with HashToPoint ( though it should have been)
   123  // there are no side-effects or degradtion of curve25519, due to this
   124  // however, the mistakes have to kept as they were in original code base
   125  // this function is only used to generate H from G
   126  func (p *Key) HashToPointSimple() (result Key) {
   127  	h := Key(Keccak256(p[:]))
   128  	extended := new(ExtendedGroupElement)
   129  	extended.FromBytes(&h)
   130  
   131  	// convert extended to projective
   132  	var p1 ProjectiveGroupElement
   133  
   134  	extended.ToProjective(&p1)
   135  	var p2 CompletedGroupElement
   136  
   137  	GeMul8(&p2, &p1)
   138  	p2.ToExtended(extended)
   139  	extended.ToBytes(&result)
   140  	return
   141  }
   142  
   143  // this uses random number generator from the OS
   144  func RandomScalar() (result *Key) {
   145  	result = new(Key)
   146  	var reduceFrom [KeyLength * 2]byte
   147  	tmp := make([]byte, KeyLength*2)
   148  	rand.Read(tmp)
   149  	copy(reduceFrom[:], tmp)
   150  	ScReduce(result, &reduceFrom)
   151  	return
   152  }
   153  
   154  // generate a new private-public key pair
   155  func NewKeyPair() (privKey *Key, pubKey *Key) {
   156  	privKey = RandomScalar()
   157  	pubKey = privKey.PublicKey()
   158  	return
   159  }
   160  
   161  func ParseKey(buf io.Reader) (result Key, err error) {
   162  	key := make([]byte, KeyLength)
   163  	if _, err = buf.Read(key); err != nil {
   164  		return
   165  	}
   166  	copy(result[:], key)
   167  	return
   168  }
   169  
   170  /*
   171     //does a * G where a is a scalar and G is the curve basepoint
   172      key scalarmultBase(const key & a) {
   173          ge_p3 point;
   174          key aG;
   175          sc_reduce32copy(aG.bytes, a.bytes); //do this beforehand
   176          ge_scalarmult_base(&point, aG.bytes);
   177          ge_p3_tobytes(aG.bytes, &point);
   178          return aG;
   179      }
   180  */
   181  //does a * G where a is a scalar and G is the curve basepoint
   182  
   183  func ScalarmultBase(a *Key) (aG *Key) {
   184  	reduce32copy := a
   185  	ScReduce32(reduce32copy)
   186  	point := new(ExtendedGroupElement)
   187  	GeScalarMultBase(point, a)
   188  	aG = new(Key)
   189  	point.ToBytes(aG)
   190  	return aG
   191  }
   192  
   193  // generates a key which can be used as private key or mask
   194  // this function is similiar to  RandomScalar except for reduce32, TODO can we merge both
   195  func skGen() Key {
   196  	skey := RandomScalar()
   197  	ScReduce32(skey)
   198  	return *skey
   199  }
   200  func SkGen() Key {
   201  	return skGen()
   202  }
   203  
   204  func (k *Key) SignedRadix16() [64]int8 {
   205  	if k[31] > 127 {
   206  		panic("scalar has high bit set illegally")
   207  	}
   208  
   209  	var digits [64]int8
   210  
   211  	// Compute unsigned radix-16 digits:
   212  	for i := 0; i < 32; i++ {
   213  		digits[2*i] = int8(k[i] & 15)
   214  		digits[2*i+1] = int8((k[i] >> 4) & 15)
   215  	}
   216  
   217  	// Recenter coefficients:
   218  	for i := 0; i < 63; i++ {
   219  		carry := (digits[i] + 8) >> 4
   220  		digits[i] -= carry << 4
   221  		digits[i+1] += carry
   222  	}
   223  
   224  	return digits
   225  }
   226  
   227  func (k *Key) ToExtended() (result *ExtendedGroupElement) {
   228  	result = new(ExtendedGroupElement)
   229  	result.FromBytes(k)
   230  	return
   231  }
   232  
   233  // bothe the function resturn identity of the ed25519 curve
   234  func identity() (result *Key) {
   235  	result = new(Key)
   236  	result[0] = 1
   237  	return
   238  }
   239  
   240  func CurveIdentity() (result Key) {
   241  	result = Identity
   242  	return result
   243  }
   244  
   245  func CurveOrder() (result Key) {
   246  	result = L
   247  	return result
   248  }
   249  
   250  // convert a uint64 to a scalar
   251  func d2h(val uint64) (result *Key) {
   252  	result = new(Key)
   253  	for i := 0; val > 0; i++ {
   254  		result[i] = byte(val & 0xFF)
   255  		val /= 256
   256  	}
   257  	return
   258  }
   259  
   260  func HashToScalar(data ...[]byte) (result *Key) {
   261  	result = new(Key)
   262  	*result = Key(Keccak256(data...))
   263  	ScReduce32(result)
   264  	return
   265  }
   266  
   267  // does a * P where a is a scalar and P is an arbitrary point
   268  func ScalarMultKey(Point *Key, scalar *Key) (result *Key) {
   269  	var P ExtendedGroupElement
   270  	P.FromBytes(Point)
   271  	var resultPoint ProjectiveGroupElement
   272  	GeScalarMult(&resultPoint, scalar, &P)
   273  	result = new(Key)
   274  	resultPoint.ToBytes(result)
   275  	return
   276  }
   277  // multiply a scalar by H (second curve point of Pedersen Commitment)
   278  func ScalarMultH(scalar *Key) (result *Key) {
   279  	h := new(ExtendedGroupElement)
   280  	h.FromBytes(&H)
   281  	resultPoint := new(ProjectiveGroupElement)
   282  	GeScalarMult(resultPoint, scalar, h)
   283  	result = new(Key)
   284  	resultPoint.ToBytes(result)
   285  	return
   286  }
   287  
   288  // add two points together
   289  func AddKeys(sum, k1, k2 *Key) {
   290  	a := k1.ToExtended()
   291  	var b CachedGroupElement
   292  	k2.ToExtended().ToCached(&b)
   293  	var c CompletedGroupElement
   294  	geAdd(&c, a, &b)
   295  	var tmp ExtendedGroupElement
   296  	c.ToExtended(&tmp)
   297  	tmp.ToBytes(sum)
   298  	return
   299  }
   300  
   301  // compute a*G + b*B
   302  func AddKeys2(result, a, b, B *Key) {
   303  	BPoint := B.ToExtended()
   304  	var RPoint ProjectiveGroupElement
   305  	GeDoubleScalarMultVartime(&RPoint, b, BPoint, a)
   306  	RPoint.ToBytes(result)
   307  	return
   308  }
   309  
   310  //addKeys3
   311  //aAbB = a*A + b*B where a, b are scalars, A, B are curve points
   312  //B must be input after applying "precomp"
   313  func AddKeys3(result *Key, a *Key, A *Key, b *Key, B_Precomputed *[8]CachedGroupElement) {
   314  	var A_Point ExtendedGroupElement
   315  	A_Point.FromBytes(A)
   316  
   317  	var result_projective ProjectiveGroupElement
   318  	GeDoubleScalarMultPrecompVartime(&result_projective, a, &A_Point, b, B_Precomputed)
   319  	result_projective.ToBytes(result)
   320  
   321  }
   322  
   323  //addKeys3_3  this is similiar to addkeys3 except it allows for use of precomputed A,B
   324  //aAbB = a*A + b*B where a, b are scalars, A, B are curve points
   325  //A,B must be input after applying "precomp"
   326  func AddKeys3_3(result *Key, a *Key, A_Precomputed *[8]CachedGroupElement, b *Key, B_Precomputed *[8]CachedGroupElement) {
   327  	var result_projective ProjectiveGroupElement
   328  	GeDoubleScalarMultPrecompVartime2(&result_projective, a, A_Precomputed, b, B_Precomputed)
   329  	result_projective.ToBytes(result)
   330  
   331  }
   332  
   333  // subtract two points A - B
   334  func SubKeys(diff, k1, k2 *Key) {
   335  	a := k1.ToExtended()
   336  	b := new(CachedGroupElement)
   337  	k2.ToExtended().ToCached(b)
   338  	c := new(CompletedGroupElement)
   339  	geSub(c, a, b)
   340  	tmp := new(ExtendedGroupElement)
   341  	c.ToExtended(tmp)
   342  	tmp.ToBytes(diff)
   343  	return
   344  }
   345  
   346  // zero fill the key
   347  func Sc_0(k *Key) {
   348  	for i := 0; i < 32; i++ {
   349  		k[i] = 0
   350  	}
   351  }
   352  
   353  // RandomPubKey takes a random scalar, interprets it as a point on the curve
   354  //  remember the low order bug and do more auditing of the entire thing
   355  func RandomPubKey() (result *Key) {
   356  	result = new(Key)
   357  	p3 := new(ExtendedGroupElement)
   358  	var p1 ProjectiveGroupElement
   359  	var p2 CompletedGroupElement
   360  	h := RandomScalar()
   361  	p1.FromBytes(h)
   362  	GeMul8(&p2, &p1)
   363  	p2.ToExtended(p3)
   364  	p3.ToBytes(result)
   365  	return
   366  }
   367  
   368  // this is the main key derivation function and is the crux
   369  // when deriving keys in the case user  A wants to send DERO to another user B ( this is outgoing case)
   370  // public key is B's view key
   371  // private keys is TX private key
   372  // if user B wants to derive key, he needs to   ( this is incoming case )
   373  // public key is TX public key
   374  // private is B's private keys
   375  // HOPE the above is  clean and clear
   376  
   377  func KeyDerivation(pub *Key, priv *Key) (KeyDerivation Key) {
   378  	var point ExtendedGroupElement
   379  	var point2 ProjectiveGroupElement
   380  	var point3 CompletedGroupElement
   381  
   382  	if !priv.Private_Key_Valid() {
   383  		panic("Invalid private key.")
   384  	}
   385  	tmp := *pub
   386  	if !point.FromBytes(&tmp) {
   387  		panic("Invalid public key.")
   388  	}
   389  
   390  	tmp = *priv
   391  	GeScalarMult(&point2, &tmp, &point)
   392  	GeMul8(&point3, &point2)
   393  	point3.ToProjective(&point2)
   394  
   395  	point2.ToBytes(&tmp)
   396  	return tmp
   397  }
   398  
   399  // the origincal c implementation needs to be checked for varint overflow
   400  // we also need to check the compatibility of golang varint with cryptonote implemented varint
   401  // outputIndex is the position of output within that specific transaction
   402  func (k *Key) KeyDerivationToScalar(outputIndex uint64) (scalar *Key) {
   403  	tmp := make([]byte, 12, 12)
   404  
   405  	length := binary.PutUvarint(tmp, outputIndex)
   406  	tmp = tmp[:length]
   407  
   408  	var buf bytes.Buffer
   409  	buf.Write(k[:])
   410  	buf.Write(tmp)
   411  	scalar = HashToScalar(buf.Bytes())
   412  	return
   413  }
   414  
   415  // generate ephermal keys  from a key derivation
   416  // base key is the B's public spend key or A's private spend key
   417  // outputIndex is the position of output within that specific transaction
   418  func (kd *Key) KeyDerivation_To_PublicKey(outputIndex uint64, baseKey Key) Key {
   419  
   420  	var point1, point2 ExtendedGroupElement
   421  	var point3 CachedGroupElement
   422  	var point4 CompletedGroupElement
   423  	var point5 ProjectiveGroupElement
   424  
   425  	tmp := baseKey
   426  	if !point1.FromBytes(&tmp) {
   427  		panic("Invalid public key.")
   428  	}
   429  	scalar := kd.KeyDerivationToScalar(outputIndex)
   430  	GeScalarMultBase(&point2, scalar)
   431  	point2.ToCached(&point3)
   432  	geAdd(&point4, &point1, &point3)
   433  	point4.ToProjective(&point5)
   434  	point5.ToBytes(&tmp)
   435  	return tmp
   436  }
   437  
   438  // generate ephermal keys  from a key derivation
   439  // base key is the A's private spend key
   440  // outputIndex is the position of output within that specific transaction
   441  func (kd *Key) KeyDerivation_To_PrivateKey(outputIndex uint64, baseKey Key) Key {
   442  	if !baseKey.Private_Key_Valid() {
   443  		panic("Invalid private key.")
   444  	}
   445  	scalar := kd.KeyDerivationToScalar(outputIndex)
   446  
   447  	tmp := baseKey
   448  	ScAdd(&tmp, &tmp, scalar)
   449  
   450  	return tmp
   451  }
   452  
   453  // NewKeyImage creates a new KeyImage from the given public and private keys.
   454  // The keys are usually the ephemeral keys derived using KeyDerivation.
   455  func GenerateKeyImage(pub Key, private Key) Key {
   456  	var proj ProjectiveGroupElement
   457  
   458  	ext := pub.HashToEC()
   459  	GeScalarMult(&proj, &private, ext)
   460  
   461  	var ki Key
   462  	proj.ToBytes(&ki)
   463  	return ki
   464  }
   465  
   466  func PreComputeForMultiScalar (p *Key) [8]CachedGroupElement {
   467  	// A,2A,3A,4A,5A,6A,7A,8A
   468  	var Ai [8]CachedGroupElement
   469  	var A ExtendedGroupElement
   470  	t := new(CompletedGroupElement)
   471  	u := new(ExtendedGroupElement)
   472  
   473  	A.FromBytes(p)
   474  	A.ToCached(&Ai[0])
   475  	for j := 0; j < 7; j++ {
   476  		geAdd(t, &A, &Ai[j])
   477  		t.ToExtended(u)
   478  		u.ToCached(&Ai[j+1])
   479  	}
   480  	return Ai
   481  }
   482  
   483  
   484  func MultiScalarMultKeyCached(AiLs [][8]CachedGroupElement, scalars []*Key, ) (result *Key) {
   485  	r := new(ProjectiveGroupElement)
   486  
   487  	digitsLs := make([][64]int8, len(scalars))
   488  	for i:= range digitsLs {
   489  		digitsLs[i] = scalars[i].SignedRadix16()
   490  	}
   491  
   492  	t := new(CompletedGroupElement)
   493  	u := new(ExtendedGroupElement)
   494  
   495  	r.Zero()
   496  	cachedBase := new(ExtendedGroupElement)
   497  	cur := new(CachedGroupElement)
   498  	minusCur := new(CachedGroupElement)
   499  	for i := 63; i >= 0; i-- {
   500  		r.Double(t)
   501  		t.ToProjective(r)
   502  		r.Double(t)
   503  		t.ToProjective(r)
   504  		r.Double(t)
   505  		t.ToProjective(r)
   506  		r.Double(t)
   507  		t.ToExtended(u)
   508  
   509  		cachedBase.Zero()
   510  		tmpt := new(CompletedGroupElement)
   511  		for j:= 0; j < len(scalars); j++ {
   512  			cur.Zero()
   513  			b := digitsLs[j][i]
   514  			bNegative := int8(negative(int32(b)))
   515  			bAbs := b - (((-bNegative) & b) << 1)
   516  
   517  			for k := int32(0); k < 8; k++ {
   518  				if equal(int32(bAbs), k+1) == 1 { // optimisation
   519  					CachedGroupElementCMove(cur, &AiLs[j][k], equal(int32(bAbs), k+1))
   520  				}
   521  			}
   522  			FeCopy(&minusCur.yPlusX, &cur.yMinusX)
   523  			FeCopy(&minusCur.yMinusX, &cur.yPlusX)
   524  			FeCopy(&minusCur.Z, &cur.Z)
   525  			FeNeg(&minusCur.T2d, &cur.T2d)
   526  			CachedGroupElementCMove(cur, minusCur, int32(bNegative))
   527  
   528  			geAdd(tmpt, cachedBase, cur)
   529  			tmpt.ToExtended(cachedBase)
   530  		}
   531  		tmpv := new(CachedGroupElement)
   532  		cachedBase.ToCached(tmpv)
   533  		geAdd(t, u, tmpv)
   534  		t.ToProjective(r)
   535  	}
   536  	result = new(Key)
   537  	r.ToBytes(result)
   538  	return result
   539  }
   540  
   541  func MultiScalarMultKey(points []*Key, scalars []*Key) (result *Key) {
   542  	r := new(ProjectiveGroupElement)
   543  
   544  
   545  	pointLs := make([]ExtendedGroupElement, len(points))
   546  
   547  	digitsLs := make([][64]int8, len(scalars))
   548  	for i:= range digitsLs {
   549  		digitsLs[i] = scalars[i].SignedRadix16()
   550  	}
   551  
   552  	AiLs := make([][8]CachedGroupElement, len(scalars))
   553  	for i:= 0; i < len(scalars); i++ {
   554  		// A,2A,3A,4A,5A,6A,7A,8A
   555  		t := new(CompletedGroupElement)
   556  		u := new(ExtendedGroupElement)
   557  		pointLs[i].FromBytes(points[i])
   558  		pointLs[i].ToCached(&AiLs[i][0])
   559  		for j := 0; j < 7; j++ {
   560  			geAdd(t, &pointLs[i], &AiLs[i][j])
   561  			t.ToExtended(u)
   562  			u.ToCached(&AiLs[i][j+1])
   563  		}
   564  	}
   565  
   566  	t := new(CompletedGroupElement)
   567  	u := new(ExtendedGroupElement)
   568  
   569  	r.Zero()
   570  	cachedBase := new(ExtendedGroupElement)
   571  	cur := new(CachedGroupElement)
   572  	minusCur := new(CachedGroupElement)
   573  	for i := 63; i >= 0; i-- {
   574  		r.Double(t)
   575  		t.ToProjective(r)
   576  		r.Double(t)
   577  		t.ToProjective(r)
   578  		r.Double(t)
   579  		t.ToProjective(r)
   580  		r.Double(t)
   581  		t.ToExtended(u)
   582  
   583  		cachedBase.Zero()
   584  		tmpt := new(CompletedGroupElement)
   585  		for j:= 0; j < len(scalars); j++ {
   586  			cur.Zero()
   587  			b := digitsLs[j][i]
   588  			bNegative := int8(negative(int32(b)))
   589  			bAbs := b - (((-bNegative) & b) << 1)
   590  
   591  			for k := int32(0); k < 8; k++ {
   592  				if equal(int32(bAbs), k+1) == 1 { // optimisation
   593  					CachedGroupElementCMove(cur, &AiLs[j][k], equal(int32(bAbs), k+1))
   594  				}
   595  			}
   596  			FeCopy(&minusCur.yPlusX, &cur.yMinusX)
   597  			FeCopy(&minusCur.yMinusX, &cur.yPlusX)
   598  			FeCopy(&minusCur.Z, &cur.Z)
   599  			FeNeg(&minusCur.T2d, &cur.T2d)
   600  			CachedGroupElementCMove(cur, minusCur, int32(bNegative))
   601  
   602  			geAdd(tmpt, cachedBase, cur)
   603  			tmpt.ToExtended(cachedBase)
   604  		}
   605  		tmpv := new(CachedGroupElement)
   606  		cachedBase.ToCached(tmpv)
   607  		geAdd(t, u, tmpv)
   608  		t.ToProjective(r)
   609  	}
   610  	result = new(Key)
   611  	r.ToBytes(result)
   612  	return result
   613  }