Skip to content

Commit

Permalink
add Crypto contract
Browse files Browse the repository at this point in the history
  • Loading branch information
turbolent committed Oct 17, 2024
1 parent 44e80f4 commit e74fbfe
Show file tree
Hide file tree
Showing 5 changed files with 380 additions and 17 deletions.
172 changes: 172 additions & 0 deletions contracts/Crypto.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@

access(all)
contract Crypto {

access(all)
fun hash(_ data: [UInt8], algorithm: HashAlgorithm): [UInt8] {
return algorithm.hash(data)
}

access(all)
fun hashWithTag(_ data: [UInt8], tag: String, algorithm: HashAlgorithm): [UInt8] {
return algorithm.hashWithTag(data, tag: tag)
}

access(all)
struct KeyListEntry {

access(all)
let keyIndex: Int

access(all)
let publicKey: PublicKey

access(all)
let hashAlgorithm: HashAlgorithm

access(all)
let weight: UFix64

access(all)
let isRevoked: Bool

init(
keyIndex: Int,
publicKey: PublicKey,
hashAlgorithm: HashAlgorithm,
weight: UFix64,
isRevoked: Bool
) {
self.keyIndex = keyIndex
self.publicKey = publicKey
self.hashAlgorithm = hashAlgorithm
self.weight = weight
self.isRevoked = isRevoked
}
}

access(all)
struct KeyList {

access(self)
let entries: [KeyListEntry]

init() {
self.entries = []
}

/// Adds a new key with the given weight
access(all)
fun add(
_ publicKey: PublicKey,
hashAlgorithm: HashAlgorithm,
weight: UFix64
): KeyListEntry {

let keyIndex = self.entries.length
let entry = KeyListEntry(
keyIndex: keyIndex,
publicKey: publicKey,
hashAlgorithm: hashAlgorithm,
weight: weight,
isRevoked: false
)
self.entries.append(entry)
return entry
}

/// Returns the key at the given index, if it exists.
/// Revoked keys are always returned, but they have the `isRevoked` field set to true
access(all)
fun get(keyIndex: Int): KeyListEntry? {
if keyIndex >= self.entries.length {
return nil
}

return self.entries[keyIndex]
}

/// Marks the key at the given index revoked, but does not delete it
access(all)
fun revoke(keyIndex: Int) {
if keyIndex >= self.entries.length {
return
}

let currentEntry = self.entries[keyIndex]
self.entries[keyIndex] = KeyListEntry(
keyIndex: currentEntry.keyIndex,
publicKey: currentEntry.publicKey,
hashAlgorithm: currentEntry.hashAlgorithm,
weight: currentEntry.weight,
isRevoked: true
)
}

/// Returns true if the given signatures are valid for the given signed data
access(all)
fun verify(
signatureSet: [KeyListSignature],
signedData: [UInt8],
domainSeparationTag: String
): Bool {

var validWeights: UFix64 = 0.0

let seenKeyIndices: {Int: Bool} = {}

for signature in signatureSet {

// Ensure the key index is valid
if signature.keyIndex >= self.entries.length {
return false
}

// Ensure this key index has not already been seen
if seenKeyIndices[signature.keyIndex] ?? false {
return false
}

// Record the key index was seen
seenKeyIndices[signature.keyIndex] = true

// Get the actual key
let key = self.entries[signature.keyIndex]

// Ensure the key is not revoked
if key.isRevoked {
return false
}

// Ensure the signature is valid
if !key.publicKey.verify(
signature: signature.signature,
signedData: signedData,
domainSeparationTag: domainSeparationTag,
hashAlgorithm:key.hashAlgorithm
) {
return false
}

validWeights = validWeights + key.weight
}

return validWeights >= 1.0
}
}

access(all)
struct KeyListSignature {

access(all)
let keyIndex: Int

access(all)
let signature: [UInt8]

init(keyIndex: Int, signature: [UInt8]) {
self.keyIndex = keyIndex
self.signature = signature
}
}
}
28 changes: 11 additions & 17 deletions lib/go/contracts/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const (
flowContractAuditsFilename = "FlowContractAudits.cdc"
flowNodeVersionBeaconFilename = "NodeVersionBeacon.cdc"
flowRandomBeaconHistoryFilename = "RandomBeaconHistory.cdc"
cryptoFilename = "Crypto.cdc"

// Test contracts
// only used for testing
Expand Down Expand Up @@ -193,8 +194,7 @@ func FlowIDTableStaking(env templates.Environment) []byte {

// FlowStakingProxy returns the StakingProxy contract.
func FlowStakingProxy() []byte {
code := assets.MustAssetString(flowStakingProxyFilename)
return []byte(code)
return assets.MustAsset(flowStakingProxyFilename)
}

// FlowStakingCollection returns the StakingCollection contract.
Expand Down Expand Up @@ -223,16 +223,12 @@ func FlowLockedTokens(

// FlowQC returns the FlowClusterQCs contract.
func FlowQC() []byte {
code := assets.MustAssetString(flowQCFilename)

return []byte(code)
return assets.MustAsset(flowQCFilename)
}

// FlowDKG returns the FlowDKG contract.
func FlowDKG() []byte {
code := assets.MustAssetString(flowDKGFilename)

return []byte(code)
return assets.MustAsset(flowDKGFilename)
}

// FlowEpoch returns the FlowEpoch contract.
Expand All @@ -246,23 +242,17 @@ func FlowEpoch(env templates.Environment) []byte {

// NodeVersionBeacon returns the NodeVersionBeacon contract content.
func NodeVersionBeacon() []byte {
code := assets.MustAssetString(flowNodeVersionBeaconFilename)

return []byte(code)
return assets.MustAsset(flowNodeVersionBeaconFilename)
}

func RandomBeaconHistory() []byte {
code := assets.MustAssetString(flowRandomBeaconHistoryFilename)

return []byte(code)
return assets.MustAsset(flowRandomBeaconHistoryFilename)
}

// FlowContractAudits returns the deprecated FlowContractAudits contract.
// This contract is no longer used on any network
func FlowContractAudits() []byte {
code := assets.MustAssetString(flowContractAuditsFilename)

return []byte(code)
return assets.MustAsset(flowContractAuditsFilename)
}

/******************** Test contracts *********************/
Expand Down Expand Up @@ -331,3 +321,7 @@ func TestFlowFees(fungibleTokenAddress, flowTokenAddress, storageFeesAddress str

return []byte(code)
}

func Crypto() []byte {
return assets.MustAsset(cryptoFilename)
}
6 changes: 6 additions & 0 deletions lib/go/contracts/contracts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,9 @@ func TestNodeVersionBeacon(t *testing.T) {
contract := contracts.NodeVersionBeacon()
assert.NotNil(t, contract)
}

func TestCrypto(t *testing.T) {
contract := contracts.Crypto()

assert.NotNil(t, contract)
}
Loading

0 comments on commit e74fbfe

Please sign in to comment.