Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Crypto contract #456

Merged
merged 6 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,11 @@ jobs:
run: flow version
- name: Update PATH
run: echo "/root/.local/bin" >> $GITHUB_PATH
- name: Run tests
- name: Run Go-based tests
run: export GOPATH=$HOME/go && make ci

- name: Install Flow CLI
run: sh -ci "$(curl -fsSL https://raw.githubusercontent.com/onflow/flow-cli/master/install.sh)"

- name: Run Cadence-based tests
run: cd contracts && flow test --cover --covercode="contracts" Crypto_test.cdc
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
}
}
}
Loading
Loading