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 }