github.com/Finschia/ostracon@v1.1.5/crypto/ed25519/migration.go (about)

     1  package ed25519
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  
     7  	"github.com/oasisprotocol/curve25519-voi/primitives/ed25519"
     8  	voivrf "github.com/oasisprotocol/curve25519-voi/primitives/ed25519/extra/ecvrf"
     9  
    10  	r2vrf "github.com/Finschia/ostracon/crypto/ed25519/internal/r2ishiguro"
    11  )
    12  
    13  // vrf w/o prove
    14  // vrf Prove() MUST use its latest implementation, while this allows
    15  // to verify the old blocks.
    16  type VrfNoProve interface {
    17  	Verify(pubKey ed25519.PublicKey, proof []byte, message []byte) (bool, []byte)
    18  	ProofToHash(proof []byte) ([]byte, error)
    19  }
    20  
    21  // following logics MUST use this instance:
    22  // - VRFVerify()
    23  // - ProofToHash()
    24  var (
    25  	globalVrf   = NewVersionedVrfNoProve()
    26  	globalVrfMu = sync.Mutex{}
    27  )
    28  
    29  func VRFVerify(pubKey ed25519.PublicKey, proof []byte, message []byte) (bool, []byte) {
    30  	globalVrfMu.Lock()
    31  	defer globalVrfMu.Unlock()
    32  	return globalVrf.Verify(pubKey, proof, message)
    33  }
    34  
    35  func ProofToHash(proof []byte) ([]byte, error) {
    36  	globalVrfMu.Lock()
    37  	defer globalVrfMu.Unlock()
    38  	return globalVrf.ProofToHash(proof)
    39  }
    40  
    41  // ValidateProof returns an error if the proof is not empty, but its
    42  // size != vrf.ProofSize.
    43  func ValidateProof(h []byte) error {
    44  	proofSize := len(h)
    45  	if proofSize != voivrf.ProofSize && proofSize != r2vrf.ProofSize {
    46  		return fmt.Errorf("expected size to be %d bytes, got %d bytes",
    47  			voivrf.ProofSize,
    48  			proofSize,
    49  		)
    50  	}
    51  	return nil
    52  }
    53  
    54  // versioned vrf have all the implementations inside.
    55  // it updates its version whenever it encounters the new proof format.
    56  // it CANNOT downgrade its version.
    57  var _ VrfNoProve = (*versionedVrfNoProve)(nil)
    58  
    59  type versionedVrfNoProve struct {
    60  	mu      sync.Mutex
    61  	version int
    62  
    63  	proofSizeToVersion map[int]int
    64  	vrfs               map[int]VrfNoProve
    65  }
    66  
    67  func NewVersionedVrfNoProve() VrfNoProve {
    68  	return &versionedVrfNoProve{
    69  		version: 0,
    70  		proofSizeToVersion: map[int]int{
    71  			r2vrf.ProofSize:  0,
    72  			voivrf.ProofSize: 1,
    73  		},
    74  		vrfs: map[int]VrfNoProve{
    75  			0: &r2VrfNoProve{},
    76  			1: &voiVrfNoProve{},
    77  		},
    78  	}
    79  }
    80  
    81  // getVersion emits error if the proof is old one.
    82  func (v *versionedVrfNoProve) getVrf(proof []byte) (VrfNoProve, error) {
    83  	v.mu.Lock()
    84  	defer v.mu.Unlock()
    85  
    86  	proofSize := len(proof)
    87  	if version, exists := v.proofSizeToVersion[proofSize]; exists && version >= v.version {
    88  		v.version = version
    89  		return v.vrfs[version], nil
    90  	}
    91  	return nil, fmt.Errorf("invalid proof size: %d", proofSize)
    92  }
    93  
    94  func (v *versionedVrfNoProve) Verify(pubKey ed25519.PublicKey, proof []byte, message []byte) (bool, []byte) {
    95  	vrf, err := v.getVrf(proof)
    96  	if err != nil {
    97  		return false, nil
    98  	}
    99  
   100  	return vrf.Verify(pubKey, proof, message)
   101  }
   102  
   103  func (v *versionedVrfNoProve) ProofToHash(proof []byte) ([]byte, error) {
   104  	vrf, err := v.getVrf(proof)
   105  	if err != nil {
   106  		return nil, err
   107  	}
   108  	return vrf.ProofToHash(proof)
   109  }
   110  
   111  // github.com/oasisprotocol/curve25519-voi
   112  var _ VrfNoProve = (*voiVrfNoProve)(nil)
   113  
   114  type voiVrfNoProve struct{}
   115  
   116  func (_ voiVrfNoProve) Verify(pubKey ed25519.PublicKey, proof []byte, message []byte) (bool, []byte) {
   117  	return voivrf.Verify(pubKey, proof, message)
   118  }
   119  
   120  func (_ voiVrfNoProve) ProofToHash(proof []byte) ([]byte, error) {
   121  	return voivrf.ProofToHash(proof)
   122  }
   123  
   124  // github.com/r2ishiguro/vrf
   125  var _ VrfNoProve = (*r2VrfNoProve)(nil)
   126  
   127  type r2VrfNoProve struct{}
   128  
   129  func (_ r2VrfNoProve) Verify(pubKey ed25519.PublicKey, proof []byte, message []byte) (bool, []byte) {
   130  	return r2vrf.Verify(pubKey, proof, message)
   131  }
   132  
   133  func (_ r2VrfNoProve) ProofToHash(proof []byte) ([]byte, error) {
   134  	return r2vrf.ProofToHash(proof)
   135  }