diff --git a/.github/workflows/tests.yml b/.github/workflows/continuous-integration.yml similarity index 71% rename from .github/workflows/tests.yml rename to .github/workflows/continuous-integration.yml index cb08162..52b7548 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/continuous-integration.yml @@ -1,4 +1,4 @@ -name: Tests +name: Continuous Integration on: push: @@ -10,11 +10,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - - uses: aiken-lang/setup-aiken@v0.1.0 + - uses: aiken-lang/setup-aiken@v1 with: - version: v1.0.29-alpha - + version: v1.1.0 - run: aiken fmt --check - run: aiken check -D - run: aiken build diff --git a/aiken.toml b/aiken.toml index 46e9b61..1301980 100644 --- a/aiken.toml +++ b/aiken.toml @@ -1,19 +1,23 @@ -name = "logicalmechanism/5eed0e1f" -version = "0.0.1" -license = "GPL-3.0" +name = "logical-mechanism/5eed0e1f" +version = "0.1.0" +compiler = "v1.1.0" +plutus = "v3" +license = "GPL-3.0-or-later" description = "Aiken contracts for project 'logicalmechanism/5eed0e1f'" [repository] -user = "logicalmechanism" +user = "logical-mechanism" project = "5eed0e1f" platform = "github" [[dependencies]] -name = "logicalmechanism/stdlib" -version = "plutus-v3" +name = "aiken-lang/stdlib" +version = "v2.0.0" source = "github" [[dependencies]] -name = "logicalmechanism/assist" -version = "plutus-v3" +name = "logical-mechanism/assist" +version = "v0.5.0" source = "github" + +[config] \ No newline at end of file diff --git a/complete_build.sh b/complete_build.sh index 9e29aec..d62adfe 100755 --- a/complete_build.sh +++ b/complete_build.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -e # create directories if dont exist @@ -14,63 +14,19 @@ rm -fr build/ || true echo -e "\033[1;34m\nBuilding Contracts \033[0m" # remove all traces -# aiken build --trace-level silent --filter-traces user-defined +aiken build --trace-level silent --filter-traces user-defined # keep the traces for testing if required -aiken build --trace-level verbose --filter-traces all +# aiken build --trace-level verbose --filter-traces all -ran="04" +ran="00" ran_cbor=$(python3 -c "import cbor2;hex_string='${ran}';data = bytes.fromhex(hex_string);encoded = cbor2.dumps(data);print(encoded.hex())") -echo -e "\033[1;33m\nBuilding Pointer Contract \033[0m" -aiken blueprint apply -o plutus.json -v pointer.params "${ran_cbor}" -aiken blueprint convert -v pointer.params > contracts/pointer_contract.plutus -cardano-cli conway transaction policyid --script-file contracts/pointer_contract.plutus > hashes/pointer.hash -echo -e "\033[1;33m Pointer Contract Hash: $(cat hashes/pointer.hash) \033[0m" - -echo -e "\033[1;33m\nBuilding Wallet Contract \033[0m" -aiken blueprint apply -o plutus.json -v wallet.params "${ran_cbor}" -aiken blueprint convert -v wallet.params > contracts/wallet_contract.plutus -cardano-cli conway transaction policyid --script-file contracts/wallet_contract.plutus > hashes/wallet.hash -echo -e "\033[1;33m Wallet Contract Hash: $(cat hashes/wallet.hash) \033[0m" +echo -e "\033[1;33m\nBuilding Contract \033[0m" +aiken blueprint apply -o plutus.json -v seedelf.contract.spend "${ran_cbor}" +aiken blueprint convert -v seedelf.contract.spend > contracts/seedelf_contract.plutus +cardano-cli conway transaction policyid --script-file contracts/seedelf_contract.plutus > hashes/seedelf.hash +echo -e "\033[1;33m Contract Hash: $(cat hashes/seedelf.hash) \033[0m" # end of build echo -e "\033[1;32m\nBuilding Complete! \033[0m" - -############################################################################### -######### THIS WILL BE REMOVED WHEN AIKEN MOVES TO V3 ######################### -############################################################################### -echo -e "\033[1;34m\nV3 HACK! \033[0m" -jq \ -'.type="PlutusScriptV3"' \ -./contracts/pointer_contract.plutus | sponge ./contracts/pointer_contract.plutus -aiken build --uplc -sed -i '1s/.*/(program/; 2s/.*/ 1.1.0/' artifacts/pointer.params.uplc -pointer_cbor=$(aiken uplc encode artifacts/pointer.params.uplc --cbor --hex) -pointer_cbor_cbor=$(python3 -c "import cbor2;hex_string='${pointer_cbor}';data = bytes.fromhex(hex_string);encoded = cbor2.dumps(data);print(encoded.hex())") - -jq \ ---arg cbor "$pointer_cbor_cbor" \ -'.cborHex=$cbor -' \ -./contracts/pointer_contract.plutus | sponge ./contracts/pointer_contract.plutus - -pointer_hash=$(python3 -c "import hashlib;hex_string='03${pointer_cbor}';data = hashlib.blake2b(bytes.fromhex(hex_string), digest_size=28).digest().hex();print(data)") -echo -n "${pointer_hash}" > hashes/pointer.hash - -jq \ -'.type="PlutusScriptV3"' \ -./contracts/wallet_contract.plutus | sponge ./contracts/wallet_contract.plutus -aiken build --uplc -sed -i '1s/.*/(program/; 2s/.*/ 1.1.0/' artifacts/wallet.params.uplc -wallet_cbor=$(aiken uplc encode artifacts/wallet.params.uplc --cbor --hex) -wallet_cbor_cbor=$(python3 -c "import cbor2;hex_string='${wallet_cbor}';data = bytes.fromhex(hex_string);encoded = cbor2.dumps(data);print(encoded.hex())") - -jq \ ---arg cbor "$wallet_cbor_cbor" \ -'.cborHex=$cbor -' \ -./contracts/wallet_contract.plutus | sponge ./contracts/wallet_contract.plutus - -wallet_hash=$(python3 -c "import hashlib;hex_string='03${wallet_cbor}';data = hashlib.blake2b(bytes.fromhex(hex_string), digest_size=28).digest().hex();print(data)") -echo -n "${wallet_hash}" > hashes/wallet.hash \ No newline at end of file diff --git a/lib/seedelf/bls.ak b/lib/seedelf/bls.ak index b678646..3fe3047 100644 --- a/lib/seedelf/bls.ak +++ b/lib/seedelf/bls.ak @@ -1,18 +1,15 @@ -//// -//// - use aiken/builtin /// The generator of the G1 group of the BLS12-381 curve. -/// This constant represents a fixed base point on the elliptic curve. pub const g1 = #"97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb" -/// Represents the additive identity (zero) in the G1 group. -pub const zero = - #"c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - /// This is mathematically equivalent to g^x mod q. pub fn pk(sk: Int) -> G1Element { builtin.bls12_381_g1_scalar_mul(sk, g1) } + +test pk_of_one_is_g1() { + let u: G1Element = pk(1) + u == g1 +} diff --git a/lib/seedelf/elgamal.ak b/lib/seedelf/elgamal.ak deleted file mode 100644 index ff8953f..0000000 --- a/lib/seedelf/elgamal.ak +++ /dev/null @@ -1,198 +0,0 @@ -//// -//// - -use aiken/builtin -use aiken/cbor -use aiken/hash -use seedelf/bls -use seedelf/types/register.{Register} - -pub type CypherText { - // encrypted point - c1: ByteArray, - c2: ByteArray, - // message hash - h: ByteArray, -} - -/// Encrypt a bls123-381 encoded message to some register using the ElGamal -/// encryption scheme. The return type is the CypherText type. -/// -/// ```aiken -/// elgamal.encryption(msg, scaler, datum) -/// ``` -pub fn encryption(msg: ByteArray, scaler: Int, datum: Register) -> CypherText { - // - // the message element - let m: G1Element = builtin.bls12_381_g1_uncompress(msg) - // - // generator element - let g: G1Element = builtin.bls12_381_g1_uncompress(datum.alpha) - // - // public key element - let u: G1Element = builtin.bls12_381_g1_uncompress(datum.beta) - // - // calculate the random scaler element as c1 - let c1: G1Element = builtin.bls12_381_g1_scalar_mul(scaler, g) - // - // calculate the s element to add to the message element - let s: G1Element = builtin.bls12_381_g1_scalar_mul(scaler, u) - // - // add m and s together as c2 - let c2: G1Element = builtin.bls12_381_g1_add(m, s) - // - // Build the cypher text element consisting of c1 and c2 - CypherText { - c1: c1 |> builtin.bls12_381_g1_compress, - c2: c2 |> builtin.bls12_381_g1_compress, - h: hash.sha3_256(msg), - } -} - -/// Prove that a user could decrypt a CypherText type using a cypher key. -/// -/// ```aiken -/// elgamal.decryption(cypher_text, cypher_key) -/// ``` -pub fn decryption_proof(cypher_text: CypherText, cypher_key: ByteArray) -> Bool { - // convert the cypher text elements - let c2: G1Element = builtin.bls12_381_g1_uncompress(cypher_text.c2) - // multiply c1 by the secret key - let s: G1Element = builtin.bls12_381_g1_uncompress(cypher_key) - // - // Find the inverse of the s point - let neg_s: G1Element = builtin.bls12_381_g1_neg(s) - // - // decrypt the msg - let m: G1Element = builtin.bls12_381_g1_add(c2, neg_s) - let msg: ByteArray = m |> builtin.bls12_381_g1_compress - // it can't be the zero point and the hashes must equal - and { - !builtin.bls12_381_g1_equal(m, bls.zero), - hash.sha3_256(msg) == cypher_text.h, - } -} - -/// Have Alice encrypt a message for Bob then Bob decrypts it. -test valid_decryption_proof() { - // - // the message Alice wants to encrypt - let msg: ByteArray = #"acab" - // - // encode the message as a point on the curve - let secret_msg: ByteArray = - bls.pk(builtin.bytearray_to_integer(True, msg)) - |> builtin.bls12_381_g1_compress - // - // a random scaler selected by Alice - let scaler: Int = - 44421586105950619360037151099874190412588687312032470042646096642156420779682 - // - // Bob's secret x - let x: Int = - 86478456268645743314319142250097583782656584143510069178425111699273215020899 - // - // Bob's Datum - let datum: Register = - Register { - alpha: bls.g1 |> builtin.bls12_381_g1_compress, - beta: bls.pk(x) |> builtin.bls12_381_g1_compress, - } - // - // Alice will encrypt the secret msg to Bob - let cypher_text: CypherText = encryption(secret_msg, scaler, datum) - // - // Bob will decrypt the msg - let c1: G1Element = builtin.bls12_381_g1_uncompress(cypher_text.c1) - // - // this would be done off chain to keep x private - let cypher_key: ByteArray = - builtin.bls12_381_g1_scalar_mul(x, c1) - |> builtin.bls12_381_g1_compress - // - // Prove that Bob could decrypt and its the correct msg - decryption_proof(cypher_text, cypher_key) -} - -/// Have Alice encrypt a message for Carol then Bob decrypts it. -test invalid_decryption_proof() fail { - // - // the message Alice wants to encrypt - let msg: ByteArray = #"acab" - // - // encode the message as a point on the curve - let secret_msg: ByteArray = - bls.pk(builtin.bytearray_to_integer(True, msg)) - |> builtin.bls12_381_g1_compress - // - // a random scaler selected by Alice - let scaler: Int = - 44421586105950619360037151099874190412588687312032470042646096642156420779682 - // - // Bob's secret x - let x: Int = - 86478456268645743314319142250097583782656584143510069178425111699273215020899 - // Carol's secret y - let y: Int = - 50097583782656584143510069178425111699273215020899864784562686457433143191422 - // - // - // Carol's Datum - let datum2: Register = - Register { - alpha: bls.g1 |> builtin.bls12_381_g1_compress, - beta: bls.pk(y) |> builtin.bls12_381_g1_compress, - } - // - // Alice will encrypt the secret msg to Carol - let cypher_text: CypherText = encryption(secret_msg, scaler, datum2) - // - // Bob will decrypt the msg - let c1: G1Element = builtin.bls12_381_g1_uncompress(cypher_text.c1) - // - // this would be done off chain to keep x private - let cypher_key: ByteArray = - builtin.bls12_381_g1_scalar_mul(x, c1) - |> builtin.bls12_381_g1_compress - // - // Prove that Bob could not decrypt the msg - decryption_proof(cypher_text, cypher_key) -} - -/// There isn't anything being encrypted here, the message is the zero point. -test no_encryption_proof() fail { - // - // Bob's secret x - let x: Int = - 86478456268645743314319142250097583782656584143510069178425111699273215020899 - // the message Alice wants to encrypt - let msg: ByteArray = #"acab" - let cypher_text: CypherText = - CypherText { - c1: bls.g1 |> builtin.bls12_381_g1_compress, - c2: bls.pk(x) |> builtin.bls12_381_g1_compress, - h: hash.sha3_256(msg), - } - // - // Bob will decrypt the msg - let c1: G1Element = builtin.bls12_381_g1_uncompress(cypher_text.c1) - // - // this would be done off chain to keep x private - let cypher_key: ByteArray = - builtin.bls12_381_g1_scalar_mul(x, c1) - |> builtin.bls12_381_g1_compress - // - // Prove that Bob could not decrypt the msg - decryption_proof(cypher_text, cypher_key) -} - -test is_a_point() { - let m: ByteArray = - #"80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000acab" - trace @"message" - trace cbor.diagnostic(m) - let c1: G1Element = builtin.bls12_381_g1_uncompress(m) - trace @"g1 element" - trace cbor.diagnostic(c1) - True -} diff --git a/lib/seedelf/signing.ak b/lib/seedelf/signing.ak deleted file mode 100644 index 9636182..0000000 --- a/lib/seedelf/signing.ak +++ /dev/null @@ -1,152 +0,0 @@ -//// -//// - -use aiken/builtin -use aiken/bytearray -use aiken/hash -use seedelf/bls -use seedelf/types/register.{Register} - -/// The zero knowledge elements required for the proof. -pub type FiatShamirRedeemer { - // this is z = r + c*x - z: ByteArray, - // this is the g^r compressed G1Element - g_r: ByteArray, -} - -/// A variation of a Fiat-Shamir signature scheme. Sign some message m using -/// a secret key but without revealing the value in the process. This uses -/// g^z = g^r * u^c, where z = r + c*x and u = g^x. -/// -/// ```aiken -/// signing.verify(msg, datum, redeemer) -/// ``` -pub fn verify(m: ByteArray, datum: Register, redeemer: FiatShamirRedeemer) -> Bool { - // - // hash the message and produce the challenge value e - let h: ByteArray = hash.sha3_256(m) - let eb: ByteArray = hash.sha3_256(bytearray.concat(h, redeemer.g_r)) - let e: Int = builtin.bytearray_to_integer(True, eb) - // - // generator element - let g: G1Element = builtin.bls12_381_g1_uncompress(datum.alpha) - // public key element - let u: G1Element = builtin.bls12_381_g1_uncompress(datum.beta) - // - // get the z integer from the redeemer - let z: Int = builtin.bytearray_to_integer(True, redeemer.z) - // the z computation: g^z = g^(r + e * x) = g^r * g^(e * x) = g^r * (g^x)^e - let g_z: G1Element = builtin.bls12_381_g1_scalar_mul(z, g) - // - // the g^r term: off-chain computation, uncompress into an element - let g_r: G1Element = builtin.bls12_381_g1_uncompress(redeemer.g_r) - // - //the u^e computation: u^e = (g^x)^e = g^(x * e) - let u_e: G1Element = builtin.bls12_381_g1_scalar_mul(e, u) - // - // the product, g^r * u^e, becomes the sum, g_r + u_e, when using bls12-381 - let rhs: G1Element = builtin.bls12_381_g1_add(g_r, u_e) - // - // check if equation: g^z = g^r * u^e -> g^z = rhs, is true - // - builtin.bls12_381_g1_equal(g_z, rhs)? -} - -test good_verify() { - // some secret x - let x: Int = - 86478456268645743314319142250097583782656584143510069178425111699273215020899 - // the datum register using the g1 generator and the public value for x - let datum: Register = - Register { - alpha: bls.g1 |> builtin.bls12_381_g1_compress, - beta: bls.pk(x) |> builtin.bls12_381_g1_compress, - } - // this message to sign - let m: ByteArray = #"acab" - // a random number - let r: Int = - 44421586105950619360037151099874190412588687312032470042646096642156420779682 - let g: G1Element = builtin.bls12_381_g1_uncompress(datum.alpha) - let g_r: G1Element = builtin.bls12_381_g1_scalar_mul(r, g) - let grb: ByteArray = g_r |> builtin.bls12_381_g1_compress - // hash the message - let h: ByteArray = hash.sha3_256(m) - // construct the e integer - let eb: ByteArray = hash.sha3_256(bytearray.concat(h, grb)) - let e: Int = builtin.bytearray_to_integer(True, eb) - // calculate z - let z: Int = r + x * e - // build zk data - let redeemer: FiatShamirRedeemer = - FiatShamirRedeemer { z: builtin.integer_to_bytearray(True, 0, z), g_r: grb } - verify(m, datum, redeemer) -} - -test rerandomized_good_verify() { - // some secret x - let x: Int = - 86478456268645743314319142250097583782656584143510069178425111699273215020899 - // the datum register using the g1 generator and the public value for x - let a0: Register = - Register { - alpha: bls.g1 |> builtin.bls12_381_g1_compress, - beta: bls.pk(x) |> builtin.bls12_381_g1_compress, - } - // The re-randomizer number - let d: Int = - 53767766789778895376051712452456827203944826866229066056242444673395870447090 - // rerandomize the a0 register - let datum: Register = register.rerandomize(a0, d) - // this message to sign - let m: ByteArray = #"acab" - // a random number - let r: Int = - 44421586105950619360037151099874190412588687312032470042646096642156420779682 - let g: G1Element = builtin.bls12_381_g1_uncompress(datum.alpha) - let g_r: G1Element = builtin.bls12_381_g1_scalar_mul(r, g) - let grb: ByteArray = g_r |> builtin.bls12_381_g1_compress - // hash the message - let h: ByteArray = hash.sha3_256(m) - // construct the e integer - let eb: ByteArray = hash.sha3_256(bytearray.concat(h, grb)) - let e: Int = builtin.bytearray_to_integer(True, eb) - // calculate z - let z: Int = r + x * e - // build zk data - let redeemer: FiatShamirRedeemer = - FiatShamirRedeemer { z: builtin.integer_to_bytearray(True, 0, z), g_r: grb } - verify(m, datum, redeemer) -} - -test bad_verify() fail { - // some secret x - let x: Int = - 86478456268645743314319142250097583782656584143510069178425111699273215020899 - // the datum register using the g1 generator and the public value for x - let datum: Register = - Register { - alpha: bls.g1 |> builtin.bls12_381_g1_compress, - beta: bls.pk(x) |> builtin.bls12_381_g1_compress, - } - // this message to sign - let m: ByteArray = #"acab" - // a random number - let r: Int = - 44421586105950619360037151099874190412588687312032470042646096642156420779682 - let g: G1Element = builtin.bls12_381_g1_uncompress(datum.alpha) - let g_r: G1Element = builtin.bls12_381_g1_scalar_mul(r, g) - let grb: ByteArray = g_r |> builtin.bls12_381_g1_compress - // hash the message - let h: ByteArray = hash.sha3_256(m) - // construct the e integer - let eb: ByteArray = hash.sha3_256(bytearray.concat(h, grb)) - let e: Int = builtin.bytearray_to_integer(True, eb) - // calculate z - let z: Int = r + x * e - // build zk data - let redeemer: FiatShamirRedeemer = - FiatShamirRedeemer { z: builtin.integer_to_bytearray(True, 0, z), g_r: grb } - verify(#"beef", datum, redeemer) -} diff --git a/lib/seedelf/spending.ak b/lib/seedelf/spending.ak index 7a064ce..f8d96ce 100644 --- a/lib/seedelf/spending.ak +++ b/lib/seedelf/spending.ak @@ -1,9 +1,6 @@ -//// -//// - use aiken/builtin -use aiken/bytearray -use aiken/hash +use aiken/crypto +use aiken/primitive/bytearray use seedelf/bls use seedelf/types/register.{Register} @@ -21,7 +18,7 @@ pub type SchnorrRedeemer { /// should be compressed g1 elements but they can also be compressed integers. /// /// ```aiken -/// spending.fiat_shamir_heuristic(gb, grb, ub) +/// fiat_shamir_heuristic(gb, grb, ub) /// ``` pub fn fiat_shamir_heuristic( // compressed g element @@ -30,17 +27,20 @@ pub fn fiat_shamir_heuristic( grb: ByteArray, // compressed g^x element ub: ByteArray, + // upper bound as bytearray + b: ByteArray, ) -> ByteArray { // concat gb, grb, and ub together then hash the result - // sha3_256 should be ok to use here + // blake2b_256 is the cheapest on chain gb |> bytearray.concat(grb) |> bytearray.concat(ub) - |> hash.sha3_256() + |> bytearray.concat(b) + |> crypto.blake2b_256() } test empty_fiat_shamir_transform() { - fiat_shamir_heuristic(#"", #"", #"") == #"a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a" + fiat_shamir_heuristic(#"", #"", #"", #"") == #"0e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a8" } test real_fiat_shamir_transform1() { @@ -48,7 +48,8 @@ test real_fiat_shamir_transform1() { #"86f0c64bd433568dd92751f0bee97feaaeee6f3c2144b210be68d2bc85253b1994703caf7f8361ccf246fef52c0ad859", #"97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", #"a2cbc5c3c72a7bc9047971345df392a67279d2f32082891976d913c699885c3ff9a90a8ea942bef4729cf93f526521e4", - ) == #"524fb8209e14641b3202adcab15bddae592b83fafc34d74abb79b572bd883930" + #"0abcdef987", + ) == #"8f00cb6558bd8e76b56d4ee9ba2e4cb04331e9b89b0667147a1886293ae98d24" } test real_fiat_shamir_transform2() { @@ -56,18 +57,23 @@ test real_fiat_shamir_transform2() { #"97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", #"81b223cea171a87feba9b7749a2df7601c5a75ae01155fadc124a2ac49099a514cf1e7d9cdc769dceab14a95bd6cb0bd", #"a09d99e02f7200526dc55ef722cc171e7aa14fc732614c02ac58d59d7026a7eb18d8798f6928ea2b513f3a4feb0c94d1", - ) == #"9e65076c75a39793e533284ff153f70540b933391d48ffe4268b785dba3bf564" + #"acab", + ) == #"8f9409d05727322c9f2d1d0adf817b8d0e3a681977edc9ab866879a4a4f8f5b9" } -/// A variation of a Schnorr signature. Prove knowledge of the secret value x -/// without revealing the value in the process. This uses g^z = g^r * u^c, -/// where z = r + c*x and u = g^x. This function uses the Fiat-Shamir heuristic -/// for non-interactivity. +/// A Schnorr proof. Prove knowledge of the secret value x without revealing +/// the value in the process. The proof uses, in multiplicative form, +/// g^z = g^r * u^c, where z = r + c*x and u = g^x. This function uses the +/// Fiat-Shamir heuristic for non-interactivity. /// /// ```aiken -/// spending.d_log(datum, redeemer) +/// schnorr_proof(datum, redeemer) /// ``` -pub fn d_log(datum: Register, redeemer: SchnorrRedeemer) -> Bool { +pub fn schnorr_proof( + datum: Register, + redeemer: SchnorrRedeemer, + bound: ByteArray, +) -> Bool { // // get the z integer from the redeemer let z: Int = builtin.bytearray_to_integer(True, redeemer.z) @@ -85,13 +91,13 @@ pub fn d_log(datum: Register, redeemer: SchnorrRedeemer) -> Bool { // // use the fiat-shamir transform to calculate c then convert it to an integer let cb: ByteArray = - fiat_shamir_heuristic(datum.alpha, redeemer.g_r, datum.beta) + fiat_shamir_heuristic(datum.alpha, redeemer.g_r, datum.beta, bound) let c: Int = builtin.bytearray_to_integer(True, cb) // // the u^c computation: u^c = (g^x)^c = g^(x * c) let u_c: G1Element = builtin.bls12_381_g1_scalar_mul(c, u) // - // the product, g^r * u^c, becomes the sum, g_r + u_c, when using bls12-381 + // the product, g^r * u^c, becomes the sum, g_r + u_c because bls12-381 let rhs: G1Element = builtin.bls12_381_g1_add(g_r, u_c) // // check if equation: g^z = g^r * u^c -> g^z = rhs, is true @@ -99,7 +105,7 @@ pub fn d_log(datum: Register, redeemer: SchnorrRedeemer) -> Bool { builtin.bls12_381_g1_equal(g_z, rhs)? } -test d_log_256_bit_secret() { +test schnorr_proof_256_bit_secret() { // some secret x let x: Int = 86478456268645743314319142250097583782656584143510069178425111699273215020899 @@ -121,6 +127,7 @@ test d_log_256_bit_secret() { a0.alpha, g_r |> builtin.bls12_381_g1_compress, a0.beta, + #"acab", ) let c: Int = builtin.bytearray_to_integer(True, cb) // the z value @@ -131,7 +138,7 @@ test d_log_256_bit_secret() { z: builtin.integer_to_bytearray(True, 0, z), g_r: g_r |> builtin.bls12_381_g1_compress, } - d_log(a0, zk) + schnorr_proof(a0, zk, #"acab") } test can_unlock_after_rerandomize() { @@ -161,6 +168,7 @@ test can_unlock_after_rerandomize() { a1.alpha, g_r |> builtin.bls12_381_g1_compress, a1.beta, + #"acab", ) // convert to an integer and do the calculation let c: Int = builtin.bytearray_to_integer(True, cb) @@ -172,7 +180,7 @@ test can_unlock_after_rerandomize() { z: builtin.integer_to_bytearray(True, 0, z), g_r: g_r |> builtin.bls12_381_g1_compress, } - d_log(a1, zk) + schnorr_proof(a1, zk, #"acab") } test cant_spend_good_verify_msg() fail { @@ -194,131 +202,29 @@ test cant_spend_good_verify_msg() fail { let g_r: G1Element = builtin.bls12_381_g1_scalar_mul(r, g) let grb: ByteArray = g_r |> builtin.bls12_381_g1_compress // hash the message - let h: ByteArray = hash.sha3_256(m) + let h: ByteArray = crypto.sha3_256(m) // construct the e integer - let eb: ByteArray = hash.sha3_256(bytearray.concat(h, grb)) + let eb: ByteArray = crypto.sha3_256(bytearray.concat(h, grb)) let e: Int = builtin.bytearray_to_integer(True, eb) // calculate z let z: Int = r + x * e // build zk data let redeemer: SchnorrRedeemer = SchnorrRedeemer { z: builtin.integer_to_bytearray(True, 0, z), g_r: grb } - d_log(datum, redeemer) + schnorr_proof(datum, redeemer, m) } -// This will check how many zk proofs can be inside one tx, its about 37 or so -test many_unlocks() { - // some secret x - let x: Int = - 86478456268645743314319142250097583782656584143510069178425111699273215020899 - // the datum register - let a0: Register = - Register { - alpha: bls.g1 |> builtin.bls12_381_g1_compress, - beta: bls.pk(x) |> builtin.bls12_381_g1_compress, - } - // The re-randomizer number - let d: Int = - 53767766789778895376051712452456827203944826866229066056242444673395870447090 - // rerandomize the a0 register - let a1: Register = register.rerandomize(a0, d) - // a random number - let r: Int = - 44421586105950619360037151099874190412588687312032470042646096642156420779682 - // calculate the g^r term off chain here - let g: G1Element = builtin.bls12_381_g1_uncompress(a1.alpha) - let g_r: G1Element = builtin.bls12_381_g1_scalar_mul(r, g) - // the challenge number using a fiat shamir transform - let cb: ByteArray = - fiat_shamir_heuristic( - a1.alpha, - g_r |> builtin.bls12_381_g1_compress, - a1.beta, - ) - // convert to an integer and do the calculation - let c: Int = builtin.bytearray_to_integer(True, cb) - // the z value - let z: Int = r + c * x - // build zk data - let zk: SchnorrRedeemer = - SchnorrRedeemer { - z: builtin.integer_to_bytearray(True, 0, z), - g_r: g_r |> builtin.bls12_381_g1_compress, - } - and { - // 1 - d_log(a1, zk), - // 2 - d_log(a1, zk), - // 3 - d_log(a1, zk), - // 4 - d_log(a1, zk), - // 5 - d_log(a1, zk), - // 6 - d_log(a1, zk), - // 7 - d_log(a1, zk), - // 8 - d_log(a1, zk), - // 9 - d_log(a1, zk), - // 10 - d_log(a1, zk), - // 11 - d_log(a1, zk), - // 12 - d_log(a1, zk), - // 13 - d_log(a1, zk), - // 14 - d_log(a1, zk), - // 15 - d_log(a1, zk), - // 16 - d_log(a1, zk), - // 17 - d_log(a1, zk), - // 18 - d_log(a1, zk), - // 19 - d_log(a1, zk), - // 20 - d_log(a1, zk), - // 21 - d_log(a1, zk), - // 22 - d_log(a1, zk), - // 23 - d_log(a1, zk), - // 24 - d_log(a1, zk), - // 25 - d_log(a1, zk), - // 26 - d_log(a1, zk), - // 27 - d_log(a1, zk), - // 28 - d_log(a1, zk), - // 29 - d_log(a1, zk), - // 30 - d_log(a1, zk), - // 31 - d_log(a1, zk), - // 32 - d_log(a1, zk), - // 33 - d_log(a1, zk), - // 34 - d_log(a1, zk), - // 35 - d_log(a1, zk), - // 36 - d_log(a1, zk), - // 37 - d_log(a1, zk), - } +test cheapest_hash() { + // PASS [mem: 805, cpu: 2467639] expensive hash + // crypto.keccak_256(#"") == #"c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" + // + // PASS [mem: 805, cpu: 1663641] cheap hash + // crypto.sha3_256(#"") == #"a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a" + // + // PASS [mem: 805, cpu: 434990] cheaper hash + // crypto.sha2_256(#"") == #"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + // + // PASS [mem: 805, cpu: 351411] cheapest hash + crypto.blake2b_256(#"") == #"0e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a8" + // } diff --git a/lib/seedelf/token_name.ak b/lib/seedelf/token_name.ak new file mode 100644 index 0000000..a621f7f --- /dev/null +++ b/lib/seedelf/token_name.ak @@ -0,0 +1,45 @@ +use aiken/primitive/bytearray +use cardano/assets.{AssetName} +use cardano/transaction.{TransactionId} + +/// Allows creating a personalized random token name. Each address has a +/// username of sorts. After the 5eed0e1f prefix the next 30 characters +/// are allowed to be customized. This allows an address to be have a +/// personalized touch while still maintaining privacy. +/// +/// +/// ```aiken +/// create(tx_hash, index, prefixes.seed, redeemer) +/// ``` +pub fn create( + txid: TransactionId, + idx: Int, + prefix: ByteArray, + personal: ByteArray, +) -> AssetName { + // prefix the txid with the index + let prepend_index: ByteArray = bytearray.push(txid, idx) + // the personal part max length is 15 + let trimmed_personal: ByteArray = bytearray.slice(personal, 0, 14) + // concat the name + let prepend_prefix: ByteArray = + prefix + |> bytearray.concat(trimmed_personal) + |> bytearray.concat(prepend_index) + // slice off the first 32 + bytearray.slice(prepend_prefix, 0, 31) +} + +test simple_token_name() { + create(#"", 0, #"", #"") == #"00" +} + +test realistic_token_name() { + create( + #"acabacabacabacabacabacabacabacabacabacabacabacabacabacab", + 69, + #"5eed0e1f", + // [AncientKraken] = 5b416e6369656e744b72616b656e5d + #"5b416e6369656e744b72616b656e5d", + ) == #"5eed0e1f5b416e6369656e744b72616b656e5d45acabacabacabacabacabacab" +} diff --git a/lib/seedelf/types/register.ak b/lib/seedelf/types/register.ak index 8f8e50e..586bda7 100644 --- a/lib/seedelf/types/register.ak +++ b/lib/seedelf/types/register.ak @@ -1,6 +1,3 @@ -//// -//// - use aiken/builtin /// Alpha is the generator and beta is the public value. The pair forms the @@ -15,10 +12,10 @@ pub type Register { /// This simulates re-randomizing a register into a new one. It is used for /// testing purposes only. This function will be used in the off-chain as it -/// is the method for creating a new private address for some user. +/// is the method for creating a new private address for some register. /// /// ```aiken -/// register.rerandomize(datum, scaler) +/// rerandomize(register, random_scaler) /// ``` pub fn rerandomize(datum: Register, rng: Int) -> Register { // get the (g, u) element in their uncompressed form diff --git a/lib/seedelf/xor.ak b/lib/seedelf/xor.ak index 06a674c..435a785 100644 --- a/lib/seedelf/xor.ak +++ b/lib/seedelf/xor.ak @@ -1,9 +1,9 @@ /// An XOR statement between two booleans `a` and `b`. This is used to prevent /// burning and minting a token at the same time. It is either just burning OR -/// just minting a token. +/// minting a token, never both. /// /// ```aiken -/// xor(a,b) +/// xor(a, b) /// ``` pub fn xor(a: Bool, b: Bool) -> Bool { and { @@ -33,3 +33,29 @@ test false_true_xor() { test true_false_xor() { xor(True, False) == True } + +test good_bracket_xor() { + xor( + { + let x = 2 + x == 2 + }, + { + let y = 1 + y == 2 + }, + ) == True +} + +test bad_bracket_xor() { + xor( + { + let x = 2 + x == 2 + }, + { + let y = 1 + y == 1 + }, + ) == False +} diff --git a/scripts/.env b/scripts/.env index 760ca96..3ee4df4 100644 --- a/scripts/.env +++ b/scripts/.env @@ -1,4 +1,4 @@ # Assumes .env.preprod and .env.mainnet are in the same directory as .env -source "$(dirname "${BASH_SOURCE[0]}")/.env.sancho" -# source "$(dirname "${BASH_SOURCE[0]}")/.env.preprod" +# source "$(dirname "${BASH_SOURCE[0]}")/.env.sancho" +source "$(dirname "${BASH_SOURCE[0]}")/.env.preprod" # source "$(dirname "${BASH_SOURCE[0]}")/.env.mainnet" \ No newline at end of file diff --git a/scripts/00_createScriptReferences.sh b/scripts/00_createScriptReferences.sh index db6b034..eb8b8bc 100755 --- a/scripts/00_createScriptReferences.sh +++ b/scripts/00_createScriptReferences.sh @@ -38,8 +38,6 @@ do # Increment the counter ((counter++)) || true - - # get the required lovelace min_utxo=$(${cli} conway transaction calculate-min-required-utxo \ --protocol-params-file ./tmp/protocol.json \ @@ -49,7 +47,6 @@ do script_reference_utxo="${script_reference_address} + ${min_utxo}" echo -e "\033[0;32m\nCreating ${file_name} Script:\n" ${script_reference_utxo} " \033[0m" - ${cli} conway transaction build-raw \ --protocol-params-file ./tmp/protocol.json \ --out-file ./tmp/tx.draft \ @@ -59,20 +56,11 @@ do --tx-out-reference-script-file ${contract} \ --fee 900000 - SIZE=$(${cli} conway query ref-script-size \ - --tx-in ${ref_tx_in} \ - ${network} \ - --output-json | jq .refInputScriptSize - ) - echo SIZE ${SIZE} - echo $(stat -c %s ${contract}) - - # this is broke FEE=$(${cli} conway transaction calculate-min-fee \ --tx-body-file ./tmp/tx.draft \ --protocol-params-file ./tmp/protocol.json \ - --reference-script-size 2500 \ - --witness-count 20) + --reference-script-size 0 \ + --witness-count 10) echo -e "\033[0;35mFEE: ${FEE} \033[0m" fee=$(echo $FEE | rev | cut -c 9- | rev) diff --git a/scripts/all_balances.sh b/scripts/all_balances.sh index f8dc7a9..f9f77c3 100755 --- a/scripts/all_balances.sh +++ b/scripts/all_balances.sh @@ -5,8 +5,8 @@ set -e source .env # wallet contract -wallet_script_path="../contracts/wallet_contract.plutus" -wallet_script_address=$(${cli} address build --payment-script-file ${wallet_script_path} ${network}) +seedelf_script_path="../contracts/seedelf_contract.plutus" +seedelf_script_address=$(${cli} address build --payment-script-file ${seedelf_script_path} ${network}) # get current parameters mkdir -p ./tmp @@ -14,10 +14,10 @@ ${cli} conway query protocol-parameters ${network} --out-file ./tmp/protocol.jso ${cli} conway query tip ${network} | jq # wallet -echo -e "\033[1;35m wallet Contract Address: \033[0m" -echo -e "\n \033[1;35m ${wallet_script_address} \033[0m \n"; -${cli} conway query utxo --address ${wallet_script_address} ${network} -${cli} conway query utxo --address ${wallet_script_address} ${network} --out-file ./tmp/current_wallet.utxo +echo -e "\033[1;35m Contract Address: \033[0m" +echo -e "\n \033[1;35m ${seedelf_script_address} \033[0m \n"; +${cli} conway query utxo --address ${seedelf_script_address} ${network} +${cli} conway query utxo --address ${seedelf_script_address} ${network} --out-file ./tmp/current.utxo # Loop through each -wallet folder for wallet_folder in wallets/*-wallet; do diff --git a/scripts/data/path_to_cli.sh b/scripts/data/path_to_cli.sh index 6c8c72d..995a8fe 100644 --- a/scripts/data/path_to_cli.sh +++ b/scripts/data/path_to_cli.sh @@ -1 +1 @@ -/home/logic/Documents/Work/LogicalMechanism/testnet-node/node-sancho/8.10.1-pre/bin/cardano-cli \ No newline at end of file +cardano-cli \ No newline at end of file diff --git a/scripts/data/path_to_socket.sh b/scripts/data/path_to_socket.sh index 4a0c9c4..2333027 100644 --- a/scripts/data/path_to_socket.sh +++ b/scripts/data/path_to_socket.sh @@ -1 +1 @@ -/home/logic/Documents/Work/LogicalMechanism/testnet-node/node-sancho/db-testnet/node.socket \ No newline at end of file +/home/logic/Documents/Work/LogicalMechanism/testnets/node-preprod/db-testnet/node.socket \ No newline at end of file diff --git a/scripts/data/pointer/pointer-redeemer.json b/scripts/data/pointer/pointer-redeemer.json index 04b300a..d200c0a 100644 --- a/scripts/data/pointer/pointer-redeemer.json +++ b/scripts/data/pointer/pointer-redeemer.json @@ -1,3 +1,3 @@ { - "bytes": "416c696365" + "bytes": "" } diff --git a/scripts/data/wallet/wallet-datum.json b/scripts/data/wallet/wallet-datum.json index de36e02..d9d6349 100644 --- a/scripts/data/wallet/wallet-datum.json +++ b/scripts/data/wallet/wallet-datum.json @@ -5,7 +5,7 @@ "bytes": "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb" }, { - "bytes": "9296a951662f749f7aa2a05bdab99922d43234a3c44818d8e1f8d2c70eed601339f82f749852e6e2ad4c0f08a4180c45" + "bytes": "a8247ce1710b566987c4a7308ac85b5b3cd55304cf3604c45e9b03b1bb04bb92bbc5732aed3af280f501af6227aebb9f" } ] } diff --git a/scripts/data/wallet/wallet-redeemer.json b/scripts/data/wallet/wallet-redeemer.json index 3f0bd65..75624ba 100644 --- a/scripts/data/wallet/wallet-redeemer.json +++ b/scripts/data/wallet/wallet-redeemer.json @@ -2,10 +2,10 @@ "constructor": 0, "fields": [ { - "bytes": "1bb162731d42c59d856fb28cf3885353ba70db159a8668ff50d1f53a77d6fa14048f88a4cb083f597df1dc719af4ac1ed10d729be48c60ee6f85b393c19ff2e4" + "bytes": "0736922ee13934300b80f3070e48d5c81510bdd8f7c33941538b81d8650dd4ee09e7091971e6a9e1e721e9f8e67a582b8ab86bd4b32e32eeb9f45a16c3c3b829" }, { - "bytes": "8219d91394c8d48f791db2b335116378d8185578b7f6c7a630e658d81a996a4b8211d98b1c5405c0c984d8a191c37364" + "bytes": "963e4ed6f7b011da6eac212d93c1f9fcf1f8e4933710698c5d2def6fd6b9988fc09b8993c723e5c901ab7c43d6396dcc" } ] } \ No newline at end of file diff --git a/scripts/py/bls12_381.py b/scripts/py/bls12_381.py index fbf664d..962e6b2 100644 --- a/scripts/py/bls12_381.py +++ b/scripts/py/bls12_381.py @@ -15,7 +15,7 @@ def data_hash(data: dict) -> str: data_str = json.dumps(data, sort_keys=True) - return hashlib.sha256(data_str.encode()).hexdigest() + return hashlib.blake2b(data_str.encode(), digest_size=32).hexdigest() def hexify(n: int) -> str: @@ -56,7 +56,7 @@ def rng(length: int = sec_param) -> int: n = secrets.randbits(length) field_order = 52435875175126190479447740508185965837690552500527637822603658699938581184513 if n > field_order: - rng(length) + return rng(length) return n @@ -93,19 +93,22 @@ def z(r: int, c: int, x: int) -> int: return r + c * x -def fiat_shamir_heuristic(gb, grb, ub): - concatenated_bytes = gb + grb + ub +def fiat_shamir_heuristic(gb, grb, ub, b): + concatenated_bytes = gb + grb + ub + b + print(concatenated_bytes) unhexed_bytes = binascii.unhexlify(concatenated_bytes) - hash_result = hashlib.sha3_256(unhexed_bytes).digest().hex() + hash_result = hashlib.blake2b(unhexed_bytes, digest_size=32).digest().hex() return hash_result -def create_dlog_zk(x: int, g: str, u: str, file_name: str = 'wallet-redeemer.json') -> None: +def create_dlog_zk(x: int, g: str, u: str, b: str, file_name: str = 'wallet-redeemer.json') -> None: + if len(b) % 2 == 1: + b = '0' + b # random r ri = rng() grb = new_g1(g, ri) # - cb = fiat_shamir_heuristic(g, grb, u) + cb = fiat_shamir_heuristic(g, grb, u, b) # print('cb', cb) # random c, change to fiat shamir later ci = int(cb, 16) @@ -144,11 +147,11 @@ def verify_dlog_zk(g, u, grb, c, z) -> bool: if __name__ == "__main__": - outcome = fiat_shamir_heuristic("", "", "") == "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a" + outcome = fiat_shamir_heuristic("", "", "") == "0e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a8" print(outcome) outcome = fiat_shamir_heuristic( "86f0c64bd433568dd92751f0bee97feaaeee6f3c2144b210be68d2bc85253b1994703caf7f8361ccf246fef52c0ad859", "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", - "a2cbc5c3c72a7bc9047971345df392a67279d2f32082891976d913c699885c3ff9a90a8ea942bef4729cf93f526521e4") == "524fb8209e14641b3202adcab15bddae592b83fafc34d74abb79b572bd883930" + "a2cbc5c3c72a7bc9047971345df392a67279d2f32082891976d913c699885c3ff9a90a8ea942bef4729cf93f526521e4") == "446cc50b0fb56f2b4ad46319e628566838622640baddd9b7df31f690b38c1410" print(outcome) diff --git a/scripts/trade_token.sh b/scripts/trade_token.sh index 025b069..12eb4a3 100755 --- a/scripts/trade_token.sh +++ b/scripts/trade_token.sh @@ -4,27 +4,12 @@ set -e # SET UP VARS HERE source .env -# rm tmp/tx.signed || True - # Addresses -sender_path="wallets/user-1-wallet/" +sender_path="wallets/reference-wallet/" sender_address=$(cat ${sender_path}payment.addr) # receiver_address=$(cat ${sender_path}payment.addr) # receiver_address=$(cat wallets/reference-wallet/payment.addr) -receiver_address="addr_test1qp6wsmzsdmdkr0gttkhq0mmc9duc9py5s9fg4p3tgslmn9rk2l066zc3rvwttenwft9rcj238chmdvw4hx0j0e9q2w8srrzt52" -# receiver_address="addr_test1vrew3fk26vrq3d25sanfl89r2ucrrp6dgk3tsntksm9pacgu662xn" - -# ENTER ASSISTS HERE -assets="1 f97431da7b760ffda3f830734d44bea09d7238c801098304c1d2a59a.283232322900bc812bab23541dfb2ea4edbd35d0357ca1a04896b088cb5fbed7" - -min_utxo=$(${cli} conway transaction calculate-min-required-utxo \ - --protocol-params-file tmp/protocol.json \ - --tx-out="${receiver_address} + 5000000 + ${assets}" | tr -dc '0-9') - -# tokens_to_be_traded="${receiver_address} + ${min_utxo} + ${assets}" -tokens_to_be_traded="${receiver_address} + 500000000" - -echo -e "\nTrading Tokens:\n" ${tokens_to_be_traded} +receiver_address="addr_test1qrvnxkaylr4upwxfxctpxpcumj0fl6fdujdc72j8sgpraa9l4gu9er4t0w7udjvt2pqngddn6q4h8h3uv38p8p9cq82qav4lmp" # # exit # @@ -50,7 +35,6 @@ FEE=$(${cli} conway transaction build \ --tx-in ${seller_tx_in} \ ${network}) - # --tx-out="${tokens_to_be_traded}" \ IFS=':' read -ra VALUE <<< "${FEE}" IFS=' ' read -ra FEE <<< "${VALUE[1]}" FEE=${FEE[1]} diff --git a/scripts/wallet/00_checkBalance.sh b/scripts/wallet/00_checkBalance.sh index 37a3c53..254205c 100755 --- a/scripts/wallet/00_checkBalance.sh +++ b/scripts/wallet/00_checkBalance.sh @@ -1,15 +1,15 @@ -#!/bin/bash +#!/usr/bin/env bash set -e # SET UP VARS HERE source ../.env -# wallet script -wallet_script_path="../../contracts/wallet_contract.plutus" -wallet_script_address=$(${cli} conway address build --payment-script-file ${wallet_script_path} ${network}) +# seedelf script +seedelf_script_path="../../contracts/seedelf_contract.plutus" +seedelf_script_address=$(${cli} conway address build --payment-script-file ${seedelf_script_path} ${network}) # the minting script policy -policy_id=$(cat ../../hashes/pointer.hash) +policy_id=$(cat ../../hashes/seedelf.hash) if [[ $# -eq 0 ]] ; then echo -e "\n \033[0;31m Please Supply A Token Name \033[0m \n"; @@ -22,12 +22,12 @@ echo -e "\033[0;32m\nFinding Balance For ${1}\n\033[0m" # get script utxo echo -e "\033[0;36m Gathering wallet UTxO Information \033[0m" ${cli} conway query utxo \ - --address ${wallet_script_address} \ + --address ${seedelf_script_address} \ ${network} \ --out-file ../tmp/script_utxo.json TXNS=$(jq length ../tmp/script_utxo.json) if [ "${TXNS}" -eq "0" ]; then - echo -e "\n \033[0;31m NO UTxOs Found At ${wallet_script_address} \033[0m \n"; + echo -e "\n \033[0;31m NO UTxOs Found At ${seedelf_script_address} \033[0m \n"; exit; fi diff --git a/scripts/wallet/01_createAddressUTxO.sh b/scripts/wallet/01_createAddress.sh similarity index 54% rename from scripts/wallet/01_createAddressUTxO.sh rename to scripts/wallet/01_createAddress.sh index 20bbfe1..c638357 100755 --- a/scripts/wallet/01_createAddressUTxO.sh +++ b/scripts/wallet/01_createAddress.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -e # SET UP VARS HERE @@ -14,12 +14,12 @@ user="user-1" user_address=$(cat ../wallets/${user}-wallet/payment.addr) user_pkh=$(${cli} conway address key-hash --payment-verification-key-file ../wallets/${user}-wallet/payment.vkey) -# wallet script -wallet_script_path="../../contracts/wallet_contract.plutus" -wallet_script_address=$(${cli} conway address build --payment-script-file ${wallet_script_path} ${network}) +# seedelf script +seedelf_script_path="../../contracts/seedelf_contract.plutus" +seedelf_script_address=$(${cli} conway address build --payment-script-file ${seedelf_script_path} ${network}) -# pointer script -pointer_script_path="../../contracts/pointer_contract.plutus" +# the minting script policy +policy_id=$(cat ../../hashes/seedelf.hash) # collat collat_address=$(cat ../wallets/collat-wallet/payment.addr) @@ -31,6 +31,7 @@ if [[ $# -eq 0 ]] ; then msg="" else msg=$(echo -n "${1}" | xxd -ps | tr -d '\n' | cut -c 1-30) + echo -e "\n \033[0;31m Personal String Is ${msg}\033[0m \n" fi # get user utxo @@ -51,7 +52,7 @@ user_tx_in=${TXIN::-8} user_starting_lovelace=$(jq '[.[] | .value.lovelace] | add' ../tmp/user_utxo.json) -echo "UTxO:" $user_tx_in +echo "User UTxO:" $user_tx_in first_utxo=$(jq -r 'keys[0]' ../tmp/user_utxo.json) string=${first_utxo} IFS='#' read -ra array <<< "$string" @@ -59,7 +60,6 @@ IFS='#' read -ra array <<< "$string" # the ordering here for the first utxo is lexicographic prefix="5eed0e1f" # personalize this to whatever you want but the max hex length is 30 characters -echo Personal Msg: ${msg} jq --arg variable "${msg}" '.bytes=$variable' ../data/pointer/pointer-redeemer.json | sponge ../data/pointer/pointer-redeemer.json # generate the token @@ -86,17 +86,14 @@ echo -e "\033[0;33m\nCreating Seed Elf: $pointer_name\n\033[0m" jq --arg variable "$(jq -r '.a' ./addrs/${token_file_name})" '.fields[0].bytes=$variable' ../data/wallet/wallet-datum.json | sponge ../data/wallet/wallet-datum.json jq --arg variable "$(jq -r '.b' ./addrs/${token_file_name})" '.fields[1].bytes=$variable' ../data/wallet/wallet-datum.json | sponge ../data/wallet/wallet-datum.json -# the minting script policy -policy_id=$(cat ../../hashes/pointer.hash) - mint_token="1 ${policy_id}.${pointer_name}" -# required_lovelace=$(${cli} conway transaction calculate-min-required-utxo \ -# --protocol-params-file ../tmp/protocol.json \ -# --tx-out-inline-datum-file ../data/wallet/wallet-datum.json \ -# --tx-out="${wallet_script_address} + 5000000 + ${mint_token}" | tr -dc '0-9') +required_lovelace=$(${cli} conway transaction calculate-min-required-utxo \ + --protocol-params-file ../tmp/protocol.json \ + --tx-out-inline-datum-file ../data/wallet/wallet-datum.json \ + --tx-out="${seedelf_script_address} + 5000000 + ${mint_token}" | tr -dc '0-9') -wallet_script_out="${wallet_script_address} + ${user_starting_lovelace} + ${mint_token}" -echo "Wallet: "${wallet_script_out} +seedelf_script_out="${seedelf_script_address} + ${required_lovelace} + ${mint_token}" +echo "SeedElf Output: "${seedelf_script_out} # # exit # @@ -114,88 +111,29 @@ if [ "${TXNS}" -eq "0" ]; then fi collat_tx_in=$(jq -r 'keys[0]' ../tmp/collat_utxo.json) -pointer_ref_utxo=$(${cli} conway transaction txid --tx-file ../tmp/utxo-pointer_contract.plutus.signed) - -# echo -e "\033[0;36m Building Tx \033[0m" -# FEE=$(${cli} conway transaction build \ -# --out-file ../tmp/tx.draft \ -# --change-address ${user_address} \ -# --tx-in-collateral ${collat_tx_in} \ -# --tx-in ${user_tx_in} \ -# --tx-out="${wallet_script_out}" \ -# --tx-out-inline-datum-file ../data/wallet/wallet-datum.json \ -# --required-signer-hash ${user_pkh} \ -# --required-signer-hash ${collat_pkh} \ -# --mint="${mint_token}" \ -# --mint-tx-in-reference="${pointer_ref_utxo}#1" \ -# --mint-plutus-script-v3 \ -# --mint-reference-tx-in-redeemer-file ../data/pointer/pointer-redeemer.json \ -# --policy-id="${policy_id}" \ -# ${network}) - -# Build Raw test -execution_unts="(0, 0)" -echo -e "\033[0;36m Building Tx \033[0m" -${cli} conway transaction build-raw \ - --out-file ../tmp/tx.draft \ - --protocol-params-file ../tmp/protocol.json \ - --tx-in-collateral ${collat_tx_in} \ - --tx-in ${user_tx_in} \ - --tx-out="${wallet_script_out}" \ - --tx-out-inline-datum-file ../data/wallet/wallet-datum.json \ - --required-signer-hash ${user_pkh} \ - --required-signer-hash ${collat_pkh} \ - --mint="${mint_token}" \ - --mint-tx-in-reference="${pointer_ref_utxo}#1" \ - --mint-plutus-script-v3 \ - --mint-reference-tx-in-redeemer-file ../data/pointer/pointer-redeemer.json \ - --mint-reference-tx-in-execution-units="${execution_unts}" \ - --policy-id="${policy_id}" \ - --fee 0 - -cpu=550000000 -mem=2000000 - -pointer_execution_unts="(${cpu}, ${mem})" -pointer_computation_fee=$(echo "0.0000721*${cpu} + 0.0577*${mem}" | bc) -pointer_computation_fee_int=$(printf "%.0f" "$pointer_computation_fee") -# -# exit -# -FEE=$(${cli} conway transaction calculate-min-fee --tx-body-file ../tmp/tx.draft ${network} --protocol-params-file ../tmp/protocol.json --reference-script-size 10000 --tx-in-count 3 --tx-out-count 3 --witness-count 2) -fee=$(echo $FEE | rev | cut -c 9- | rev) +seedelf_ref_utxo=$(${cli} conway transaction txid --tx-file ../tmp/utxo-seedelf_contract.plutus.signed) -total_fee=$((${fee} + ${pointer_computation_fee_int} + 250000)) -echo Tx Fee: $total_fee -change_value=$((${user_starting_lovelace} - ${total_fee})) -wallet_script_out="${wallet_script_address} + ${change_value} + ${mint_token}" -echo "Without Fee: Wallet OUTPUT: "${wallet_script_out} - -# -# exit -# - -${cli} conway transaction build-raw \ +echo -e "\033[0;36m Building Tx \033[0m" +FEE=$(${cli} conway transaction build \ --out-file ../tmp/tx.draft \ - --protocol-params-file ../tmp/protocol.json \ + --change-address ${user_address} \ --tx-in-collateral ${collat_tx_in} \ --tx-in ${user_tx_in} \ - --tx-out="${wallet_script_out}" \ + --tx-out="${seedelf_script_out}" \ --tx-out-inline-datum-file ../data/wallet/wallet-datum.json \ --required-signer-hash ${user_pkh} \ --required-signer-hash ${collat_pkh} \ --mint="${mint_token}" \ - --mint-tx-in-reference="${pointer_ref_utxo}#1" \ + --mint-tx-in-reference="${seedelf_ref_utxo}#1" \ --mint-plutus-script-v3 \ --mint-reference-tx-in-redeemer-file ../data/pointer/pointer-redeemer.json \ - --mint-reference-tx-in-execution-units="${pointer_execution_unts}" \ --policy-id="${policy_id}" \ - --fee ${total_fee} + ${network}) -# IFS=':' read -ra VALUE <<< "${FEE}" -# IFS=' ' read -ra FEE <<< "${VALUE[1]}" -# FEE=${FEE[1]} -# echo -e "\033[1;32m Fee: \033[0m" $FEE +IFS=':' read -ra VALUE <<< "${FEE}" +IFS=' ' read -ra FEE <<< "${VALUE[1]}" +FEE=${FEE[1]} +echo -e "\033[1;32m Fee: \033[0m" $FEE # # exit # @@ -215,4 +153,4 @@ ${cli} conway transaction submit \ --tx-file ../tmp/tx.signed tx=$(${cli} conway transaction txid --tx-file ../tmp/tx.signed) -echo "Tx Hash:" $tx +echo "TxId:" $tx diff --git a/scripts/wallet/02_burnAddress.sh b/scripts/wallet/02_burnAddress.sh index c67f1e9..16dbcc3 100755 --- a/scripts/wallet/02_burnAddress.sh +++ b/scripts/wallet/02_burnAddress.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -e # SET UP VARS HERE @@ -12,19 +12,16 @@ user="user-1" user_address=$(cat ../wallets/${user}-wallet/payment.addr) user_pkh=$(${cli} conway address key-hash --payment-verification-key-file ../wallets/${user}-wallet/payment.vkey) -# walletscript -wallet_script_path="../../contracts/wallet_contract.plutus" -wallet_script_address=$(${cli} conway address build --payment-script-file ${wallet_script_path} ${network}) +# seedelf script +seedelf_script_path="../../contracts/seedelf_contract.plutus" +seedelf_script_address=$(${cli} conway address build --payment-script-file ${seedelf_script_path} ${network}) # collat collat_address=$(cat ../wallets/collat-wallet/payment.addr) collat_pkh=$(${cli} conway address key-hash --payment-verification-key-file ../wallets/collat-wallet/payment.vkey) -# pointer script -pointer_script_path="../../contracts/pointer_contract.plutus" - # the minting script policy -policy_id=$(cat ../../hashes/pointer.hash) +policy_id=$(cat ../../hashes/seedelf.hash) if [[ $# -eq 0 ]] ; then echo -e "\n \033[0;31m Please Supply A Token Name \033[0m \n"; @@ -37,12 +34,12 @@ echo -e "\033[0;33m\nBurning Seed Elf: ${1}\n\033[0m" # get script utxo echo -e "\033[0;36m Gathering wallet UTxO Information \033[0m" ${cli} conway query utxo \ - --address ${wallet_script_address} \ + --address ${seedelf_script_address} \ ${network} \ --out-file ../tmp/script_utxo.json TXNS=$(jq length ../tmp/script_utxo.json) if [ "${TXNS}" -eq "0" ]; then - echo -e "\n \033[0;31m NO UTxOs Found At ${wallet_script_address} \033[0m \n"; + echo -e "\n \033[0;31m NO UTxOs Found At ${seedelf_script_address} \033[0m \n"; exit; fi @@ -67,11 +64,34 @@ print(g) ") echo Public: ${public} +that_slot=$(python3 -c " +from datetime import datetime, timedelta, timezone + +# Get current UTC time +current_time = datetime.now(timezone.utc) +# Add specified seconds +future_time = current_time + timedelta(seconds=40) + +# Format and print in YYYY-MM-DDThh:mm:ssZ format +formatted_time = future_time.strftime('%Y-%m-%dT%H:%M:%S') + 'Z' +print(formatted_time) +") +final_slot=$(${cli} conway query slot-number ${network} ${that_slot}) +echo "Invalid at Slot:" ${final_slot} +${cli} conway query tip ${network} | jq .slot + +that_time=$(python3 -c " +from datetime import datetime, timezone +dt = datetime.strptime('${that_slot}', '%Y-%m-%dT%H:%M:%SZ') +dt = dt.replace(tzinfo=timezone.utc) +print(1000 * int(dt.timestamp())) +") + python3 -c " import sys; sys.path.append('../py/'); import bls12_381; -bls12_381.create_dlog_zk(${secret_key}, '${generator}', '${public}'); +bls12_381.create_dlog_zk(${secret_key}, '${generator}', '${public}', hex(${that_time})[2:]); " wallet_tx_in=$(python3 -c " @@ -118,11 +138,9 @@ fi collat_tx_in=$(jq -r 'keys[0]' ../tmp/collat_utxo.json) # script reference utxo -wallet_ref_utxo=$(${cli} conway transaction txid --tx-file ../tmp/utxo-wallet_contract.plutus.signed) -pointer_ref_utxo=$(${cli} conway transaction txid --tx-file ../tmp/utxo-pointer_contract.plutus.signed) +script_ref_utxo=$(${cli} conway transaction txid --tx-file ../tmp/utxo-seedelf_contract.plutus.signed) -echo Wallet Reference UTxO: ${wallet_ref_utxo} -echo Pointer Reference UTxO: ${pointer_ref_utxo} +echo Reference UTxO: ${script_ref_utxo} mint_token="-1 ${policy_id}.${1}" echo Burning: ${mint_token} @@ -132,18 +150,19 @@ jq --arg variable "" '.bytes=$variable' ../data/pointer/pointer-redeemer.json | echo -e "\033[0;36m Building Tx \033[0m" FEE=$(${cli} conway transaction build \ --out-file ../tmp/tx.draft \ + --invalid-hereafter ${final_slot} \ --change-address ${user_address} \ --tx-in-collateral ${collat_tx_in} \ --tx-in ${user_tx_in} \ --tx-in ${wallet_tx_in} \ - --spending-tx-in-reference="${wallet_ref_utxo}#1" \ + --spending-tx-in-reference="${script_ref_utxo}#1" \ --spending-plutus-script-v3 \ --spending-reference-tx-in-inline-datum-present \ --spending-reference-tx-in-redeemer-file ../data/wallet/wallet-redeemer.json \ --required-signer-hash ${user_pkh} \ --required-signer-hash ${collat_pkh} \ --mint="${mint_token}" \ - --mint-tx-in-reference="${pointer_ref_utxo}#1" \ + --mint-tx-in-reference="${script_ref_utxo}#1" \ --mint-plutus-script-v3 \ --policy-id="${policy_id}" \ --mint-reference-tx-in-redeemer-file ../data/pointer/pointer-redeemer.json \ @@ -171,7 +190,5 @@ ${cli} conway transaction submit \ ${network} \ --tx-file ../tmp/tx.signed -tx=$(cardano-cli transaction txid --tx-file ../tmp/tx.signed) -echo "Tx Hash:" $tx - -rm addrs/${token_file_name} \ No newline at end of file +tx=$(${cli} transaction txid --tx-file ../tmp/tx.signed) +echo "TxId:" $tx diff --git a/scripts/wallet/03_sendToSeedElf.sh b/scripts/wallet/03_sendToSeedElf.sh index 916b573..b85baca 100755 --- a/scripts/wallet/03_sendToSeedElf.sh +++ b/scripts/wallet/03_sendToSeedElf.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -e # SET UP VARS HERE @@ -8,13 +8,13 @@ source ../.env ${cli} conway query protocol-parameters ${network} --out-file ../tmp/protocol.json # user -user="user-1" +user="user-2" user_address=$(cat ../wallets/${user}-wallet/payment.addr) user_pkh=$(${cli} conway address key-hash --payment-verification-key-file ../wallets/${user}-wallet/payment.vkey) -# walletscript -wallet_script_path="../../contracts/wallet_contract.plutus" -wallet_script_address=$(${cli} conway address build --payment-script-file ${wallet_script_path} ${network}) +# seedelf script +seedelf_script_path="../../contracts/seedelf_contract.plutus" +seedelf_script_address=$(${cli} conway address build --payment-script-file ${seedelf_script_path} ${network}) if [[ $# -ne 2 ]] ; then echo -e "\n \033[0;31m Please Supply A Token Name and Amount \033[0m \n" @@ -34,23 +34,23 @@ if [[ $2 -lt 2000000 ]] ; then exit 1 fi -echo -e "\033[0;33m\nSending Funds To Seed Elf: ${1}\n\033[0m" +echo -e "\033[0;33m\nSending ${2} Lovelace To Seed Elf: ${1}\n\033[0m" # the minting script policy -policy_id=$(cat ../../hashes/pointer.hash) +policy_id=$(cat ../../hashes/seedelf.hash) -wallet_script_out="${wallet_script_address} + ${2}" -echo "Wallet: "${wallet_script_out} +seedelf_script_out="${seedelf_script_address} + ${2}" +echo "SeedElf Output: "${seedelf_script_out} # get script utxo echo -e "\033[0;36m Gathering wallet UTxO Information \033[0m" ${cli} conway query utxo \ - --address ${wallet_script_address} \ + --address ${seedelf_script_address} \ ${network} \ --out-file ../tmp/script_utxo.json TXNS=$(jq length ../tmp/script_utxo.json) if [ "${TXNS}" -eq "0" ]; then - echo -e "\n \033[0;31m NO UTxOs Found At ${wallet_script_address} \033[0m \n"; + echo -e "\n \033[0;31m NO UTxOs Found At ${seedelf_script_address} \033[0m \n"; exit; fi @@ -84,7 +84,7 @@ FEE=$(${cli} conway transaction build \ --out-file ../tmp/tx.draft \ --change-address ${user_address} \ --tx-in ${user_tx_in} \ - --tx-out="${wallet_script_out}" \ + --tx-out="${seedelf_script_out}" \ --tx-out-inline-datum-file ../data/wallet/wallet-datum.json \ --required-signer-hash ${user_pkh} \ ${network}) diff --git a/scripts/wallet/04_spendFunds.sh b/scripts/wallet/04_spendFunds.sh index 40353b3..662b759 100755 --- a/scripts/wallet/04_spendFunds.sh +++ b/scripts/wallet/04_spendFunds.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -e # SET UP VARS HERE @@ -7,35 +7,42 @@ source ../.env # get params ${cli} conway query protocol-parameters ${network} --out-file ../tmp/protocol.json -# walletscript -wallet_script_path="../../contracts/wallet_contract.plutus" -wallet_script_address=$(${cli} conway address build --payment-script-file ${wallet_script_path} ${network}) +# seedelf script +seedelf_script_path="../../contracts/seedelf_contract.plutus" +seedelf_script_address=$(${cli} conway address build --payment-script-file ${seedelf_script_path} ${network}) # collat collat_address=$(cat ../wallets/collat-wallet/payment.addr) collat_pkh=$(${cli} conway address key-hash --payment-verification-key-file ../wallets/collat-wallet/payment.vkey) # the minting script policy -policy_id=$(cat ../../hashes/pointer.hash) +policy_id=$(cat ../../hashes/seedelf.hash) -if [[ $# -ne 2 ]] ; then - echo -e "\n \033[0;31m Please Supply A Source Token Name And Destination Token Name \033[0m \n" - echo -e "\n \033[0;31m ./04_spendFunds.sh your_seed_elf their_seed_elf \033[0m \n" +if [[ $# -ne 3 ]] ; then + echo -e "\n \033[0;31m Please Supply A Source Token Name, Destination Token Name/Address, And Amount \033[0m \n" + echo -e "\n \033[0;31m ./04_spendFunds.sh your_seed_elf their_seed_elf/address amount \033[0m \n" exit fi +prefix="addr_" +if [[ ${2} == $prefix* ]]; then + echo -e "\033[0;33m\nSending ${3} Lovelace To Address: ${2}\n\033[0m" + +else + echo -e "\033[0;33m\nSending ${3} Lovelace To Seed Elf: ${2}\n\033[0m" +fi + token_file_name="${1}.json" -echo -e "\033[0;33m\nSending Funds To Seed Elf: ${1}\n\033[0m" # get script utxo echo -e "\033[0;36m Gathering wallet UTxO Information \033[0m" ${cli} conway query utxo \ - --address ${wallet_script_address} \ + --address ${seedelf_script_address} \ ${network} \ --out-file ../tmp/script_utxo.json TXNS=$(jq length ../tmp/script_utxo.json) if [ "${TXNS}" -eq "0" ]; then - echo -e "\n \033[0;31m NO UTxOs Found At ${wallet_script_address} \033[0m \n"; + echo -e "\n \033[0;31m NO UTxOs Found At ${seedelf_script_address} \033[0m \n"; . exit; fi @@ -67,7 +74,10 @@ fi collat_tx_in=$(jq -r 'keys[0]' ../tmp/collat_utxo.json) # script reference utxo -wallet_ref_utxo=$(${cli} conway transaction txid --tx-file ../tmp/utxo-wallet_contract.plutus.signed) +script_ref_utxo=$(${cli} conway transaction txid --tx-file ../tmp/utxo-wallet_contract.plutus.signed) + +# --tx-out="${seedelf_script_out}" \ +# --tx-out-inline-datum-file ../data/wallet/wallet-datum.json \ echo -e "\033[0;36m Building Tx \033[0m" FEE=$(${cli} conway transaction build \ @@ -75,11 +85,10 @@ FEE=$(${cli} conway transaction build \ --change-address ${user_address} \ --tx-in-collateral ${collat_tx_in} \ --tx-in ${wallet_tx_in} \ - --spending-tx-in-reference="${wallet_ref_utxo}#1" \ + --spending-tx-in-reference="${script_ref_utxo}#1" \ --spending-plutus-script-v3 \ --spending-reference-tx-in-inline-datum-present \ --spending-reference-tx-in-redeemer-file ../data/wallet/wallet-redeemer.json \ - --required-signer-hash ${user_pkh} \ --required-signer-hash ${collat_pkh} \ ${network}) diff --git a/validators/pointer.ak b/validators/pointer.ak deleted file mode 100644 index 5e1a68c..0000000 --- a/validators/pointer.ak +++ /dev/null @@ -1,88 +0,0 @@ -//// This minter is used to define a specific register in the wallet contract. -//// Its an open policy for minting and burning but each token will always -//// be unique. It use case is as a place holder for the address. A user can -//// display the token name as their address then another user may locate the -//// utxo that holds the nft and obtain the Register datum. This datum is then -//// used to produce a private address for the user. A single user may have -//// multiple pointer addresses and can delete them whenever by simply burning -//// the pointer token. This is more convenience then mandatory for the wallet -//// to function properly. -//// - -use aiken/bytearray -use aiken/transaction.{Mint, ScriptContext, Transaction} -use aiken/transaction/value.{AssetName, PolicyId} -use assist/find -use assist/minting -use assist/prefixes -use assist/types/hashes.{TxHash} -use seedelf/xor.{xor} - -// Allows creating a personalized random token name. Each address has a -// username of sorts. After the 5eed0e1f prefix the next 30 characters -// are allowed to be customized. This allows an address to be have a -// personalized touch while still maintaining privacy. -// -fn create_token_name( - txid: TxHash, - idx: Int, - prefix: ByteArray, - personal: ByteArray, -) -> AssetName { - // prefix the txid with the index - let prepend_index: ByteArray = bytearray.push(txid, idx) - // the personal part max length is 15 - let trimmed_personal: ByteArray = bytearray.slice(personal, 0, 14) - // concat the name - let prepend_prefix: ByteArray = - prefix - |> bytearray.concat(trimmed_personal) - |> bytearray.concat(prepend_index) - // slice off the first 32 - bytearray.slice(prepend_prefix, 0, 31) -} - -test simple_token_name() { - create_token_name(#"", 0, #"", #"") == #"00" -} - -test realistic_token_name() { - create_token_name( - #"1a4a1746acaf1442711e82d8049f9b62145bf91f9ed2d9dcc7eb30db22b597ba", - 69, - #"5eed0e1f", - #"5b416e6369656e744b72616b656e5d", - ) == #"5eed0e1f5b416e6369656e744b72616b656e5d451a4a1746acaf1442711e82d8" -} - -validator( - // this allows a custom policy id to be grinded out - _random_string: ByteArray, -) { - fn params(redeemer: ByteArray, context: ScriptContext) -> Bool { - expect Mint(currency_symbol) = context.purpose - // - // Burn 1 by the seed prefix xor mint 1 with the token name. - // - xor( - { - // you can burn a token with 5eed0e1f prefix - let Transaction { mint, .. } = context.transaction - let minted_value: List<(PolicyId, AssetName, Int)> = - mint |> value.flatten() - minting.by_prefix(minted_value, currency_symbol, prefixes.seed, -1)? - }, - { - // or mint one - let Transaction { inputs, mint, .. } = context.transaction - let minted_value: List<(PolicyId, AssetName, Int)> = - mint |> value.flatten() - let tx_hash: TxHash = find.first_input_txid(inputs) - let index: Int = find.first_input_index(inputs) - let token_name: AssetName = - create_token_name(tx_hash, index, prefixes.seed, redeemer) - minting.exact(minted_value, currency_symbol, token_name, 1)? - }, - ) - } -} diff --git a/validators/seedelf.ak b/validators/seedelf.ak new file mode 100644 index 0000000..3a509b4 --- /dev/null +++ b/validators/seedelf.ak @@ -0,0 +1,94 @@ +//// A UTxO may be spent if and only if a user can provide the proper ZK +//// elements to prove that g^z = g^r * u^c for a given (g, u) Register. +//// It is assumed that the set of all elements (g, u) are unique such that +//// no two datums have the same hash. This should allow an arbitrary amount +//// of UTxOs to be spent inside a single tx, allowing the contract to act like +//// a wallet for some user who knows a secret value x. This user can always +//// find their UTxOs by searching all register's for a (g, u) element where +//// g^x = u. Another user can send a UTxO to the (g, u) element by selecting a +//// large random integer d then doing the transformation, +//// (g, u) -> (g^d, u^d). This perserves the g and u relationship while +//// providing privacy as the new element, (g^d, u^d), can not be inverted into +//// the original (g, u) element. +//// +//// The minter is used to define a specific register in the wallet contract. +//// Its an open policy for minting and burning but each token will always +//// be unique. It use case is as a place holder for the address. A user can +//// display the token name as their address then another user may locate the +//// utxo that holds the nft and obtain the Register datum. This datum is then +//// used to produce a private address for the user. A single user may have +//// multiple pointer addresses and can delete them whenever by simply burning +//// the pointer token. This is more convenience then mandatory for the wallet +//// to function properly. +//// + +use aiken/interval.{Finite} +use cardano/assets.{AssetName, PolicyId} +use cardano/minting +use cardano/transaction.{OutputReference, Transaction, TransactionId} +use maths/routines +use seedelf/spending.{SchnorrRedeemer} +use seedelf/token_name +use seedelf/types/register.{Register} +use seedelf/xor.{xor} +use types/prefixes +use validation/find + +validator contract(_random: ByteArray) { + spend( + maybe_datum: Option, + redeemer: SchnorrRedeemer, + _output_ref: OutputReference, + transaction: Transaction, + ) { + // + // Spend with Schnorr Proof if the datum is of type Register using the + // upper bound as a one-time pad for the Fiat-shamir transform. + // + when maybe_datum is { + Some(datum) -> + if datum is Register { + // correct data structures are only spendable with valid schnorr proofs + let Transaction { validity_range, .. } = transaction + expect Finite(upper_bound) = validity_range.upper_bound.bound_type + let bound: ByteArray = routines.from_int(upper_bound) + spending.schnorr_proof(datum, redeemer, bound)? + } else { + // incorrect data structures should be spendable + True + } + // missing data structures should be spendable + None -> True + } + } + + mint(redeemer: ByteArray, policy_id: PolicyId, transaction: Transaction) { + // + // Burn 1 by the seed prefix xor mint 1 with the token name. + // + xor( + { + // you can burn a token with the 5eed0e1f prefix + let Transaction { mint, .. } = transaction + let minted_assets: List<(PolicyId, AssetName, Int)> = + mint |> assets.flatten() + minting.by_prefix(minted_assets, policy_id, prefixes.seed, -1)? + }, + { + // or mint a token with the 5eed0e1f prefix + let Transaction { inputs, mint, .. } = transaction + let minted_assets: List<(PolicyId, AssetName, Int)> = + mint |> assets.flatten() + let tx_hash: TransactionId = find.first_input_txid(inputs) + let index: Int = find.first_input_index(inputs) + let token_name: AssetName = + token_name.create(tx_hash, index, prefixes.seed, redeemer) + minting.exact(minted_assets, policy_id, token_name, 1)? + }, + ) + } + + else(_) { + fail + } +} diff --git a/validators/wallet.ak b/validators/wallet.ak deleted file mode 100644 index 78627d1..0000000 --- a/validators/wallet.ak +++ /dev/null @@ -1,31 +0,0 @@ -//// A UTxO may be spent if and only if a user can provide the proper ZK -//// elements to prove that g^z = g^r * u^c for a given (g, u) Register. -//// It is assumed that the set of all elements (g, u) are unique such that -//// no two datums have the same hash. This should allow an arbitrary amount -//// of UTxOs to be spent inside a single tx, allowing the contract to act like -//// a wallet for some user who knows a secret value x. This user can always -//// find their UTxOs by searching all register's for a (g, u) element where -//// g^x = u. Another user can send a UTxO to the (g, u) element by selecting a -//// large random integer d then doing the transformation, -//// (g, u) -> (g^d, u^d). This perserves the g and u relationship while -//// providing privacy as the new element, (g^d, u^d), can not be inverted into -//// the original (g, u) element. -//// - -use aiken/transaction.{ScriptContext, Spend} -use seedelf/spending.{SchnorrRedeemer} -use seedelf/types/register.{Register} - -validator( - // this allows many wallet contracts to exist - _random_string: ByteArray, -) { - fn params( - datum: Register, - redeemer: SchnorrRedeemer, - context: ScriptContext, - ) -> Bool { - expect Spend(_) = context.purpose - spending.d_log(datum, redeemer)? - } -}