github.com/zntrio/harp/v2@v2.0.9/pkg/sdk/security/crypto/extra25519/convert.go (about)

     1  // Licensed to Elasticsearch B.V. under one or more contributor
     2  // license agreements. See the NOTICE file distributed with
     3  // this work for additional information regarding copyright
     4  // ownership. Elasticsearch B.V. licenses this file to you under
     5  // the Apache License, Version 2.0 (the "License"); you may
     6  // not use this file except in compliance with the License.
     7  // You may obtain a copy of the License at
     8  //
     9  //     http://www.apache.org/licenses/LICENSE-2.0
    10  //
    11  // Unless required by applicable law or agreed to in writing,
    12  // software distributed under the License is distributed on an
    13  // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    14  // KIND, either express or implied.  See the License for the
    15  // specific language governing permissions and limitations
    16  // under the License.
    17  
    18  package extra25519
    19  
    20  import (
    21  	"crypto/ed25519"
    22  	"crypto/sha512"
    23  
    24  	"filippo.io/edwards25519"
    25  )
    26  
    27  // edBlacklist is a list of elements of the ed25519 curve that have low order.
    28  // The list was copied from https://github.com/jedisct1/libsodium/blob/141288535127c22162944e12fcadb8bc269671cc/src/libsodium/crypto_core/ed25519/ref10/ed25519_ref10.c
    29  var edBlacklist = [7][32]byte{
    30  	/* 0 (order 4) */ {
    31  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    32  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    33  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    34  	},
    35  	/* 1 (order 1) */
    36  	{
    37  		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    38  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    39  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    40  	},
    41  	/* 2707385501144840649318225287225658788936804267575313519463743609750303402022
    42  	   (order 8) */
    43  	{
    44  		0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, 0x45, 0xc3, 0xf4,
    45  		0x89, 0xf2, 0xef, 0x98, 0xf0, 0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6,
    46  		0x33, 0x39, 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x05,
    47  	},
    48  	/* 55188659117513257062467267217118295137698188065244968500265048394206261417927
    49  	   (order 8) */
    50  	{
    51  		0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 0xba, 0x3c, 0x0b,
    52  		0x76, 0x0d, 0x10, 0x67, 0x0f, 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39,
    53  		0xcc, 0xc6, 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0x7a,
    54  	},
    55  	/* p-1 (order 2) */
    56  	{
    57  		0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    58  		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    59  		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
    60  	},
    61  	/* p (=0, order 4) */
    62  	{
    63  		0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    64  		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    65  		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
    66  	},
    67  	/* p+1 (=1, order 1) */
    68  	{
    69  		0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    70  		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    71  		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
    72  	},
    73  }
    74  
    75  // IsLowOrder checks if the passed group element is of low order.
    76  // Algorithm translated from the same source as the blacklist (see above).
    77  func IsEdLowOrder(ge []byte) bool {
    78  	var (
    79  		c    [7]byte
    80  		k    int
    81  		i, j int
    82  	)
    83  
    84  	// cases j = 0..30
    85  	for j = 0; j < 31; j++ {
    86  		for i = 0; i < len(edBlacklist); i++ {
    87  			c[i] |= ge[j] ^ edBlacklist[i][j]
    88  		}
    89  	}
    90  
    91  	// case j = 31, ignore highest bit
    92  	for i = 0; i < len(edBlacklist); i++ {
    93  		c[i] |= (ge[j] & 0x7f) ^ edBlacklist[i][j]
    94  	}
    95  
    96  	k = 0
    97  	for i = 0; i < len(edBlacklist); i++ {
    98  		k |= int(c[i]) - 1
    99  	}
   100  
   101  	return ((k >> 8) & 1) == 1
   102  }
   103  
   104  // PrivateKeyToCurve25519 converts an Ed25519 private key into a corresponding
   105  // curve25519 private key such that the resulting curve25519 public key will
   106  // equal the result from PublicKeyToCurve25519.
   107  func PrivateKeyToCurve25519(curve25519Private *[32]byte, privateKey ed25519.PrivateKey) {
   108  	h := sha512.New()
   109  	h.Write(privateKey[:32])
   110  	digest := h.Sum(nil)
   111  
   112  	digest[0] &= 248
   113  	digest[31] &= 127
   114  	digest[31] |= 64
   115  
   116  	copy(curve25519Private[:], digest)
   117  }
   118  
   119  // PublicKeyToCurve25519 converts an Ed25519 public key into the curve25519
   120  // public key that would be generated from the same private key.
   121  func PublicKeyToCurve25519(curveBytes *[32]byte, edBytes ed25519.PublicKey) bool {
   122  	if IsEdLowOrder(edBytes) {
   123  		return false
   124  	}
   125  
   126  	edPoint, err := new(edwards25519.Point).SetBytes(edBytes)
   127  	if err != nil {
   128  		return false
   129  	}
   130  
   131  	copy(curveBytes[:], edPoint.BytesMontgomery())
   132  	return true
   133  }