Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
skilesare committed Jul 19, 2024
0 parents commit b6c83f3
Show file tree
Hide file tree
Showing 8 changed files with 426 additions and 0 deletions.
13 changes: 13 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Copyright 2024 ICDevs.org - forked from Deland-Labs

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
20 changes: 20 additions & 0 deletions dfx.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"version": 1,
"canisters": {
"test": {
"type": "motoko",
"main": "tests/ActorTest.mo",
"args": "-v --compacting-gc"
}
},
"defaults": {
"build": {
"packtool": "mops sources",
"args": ""
},
"replica": {
"subnet_type": "system"
}
}

}
13 changes: 13 additions & 0 deletions mops.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[dependencies]
base = "0.11.1"

[dev-dependencies]
test = "1.2.0"
fuzz = "0.2.1"

[package]
name = "principal-ext"
version = "0.1.0"
description = "Extensions for Principal"
repository = "https://github.com/icdevsorg/principal-ext.mo"
keywords = [ "prinicipal"]
52 changes: 52 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
This library has been forked from https://github.com/Deland-Labs/fungible-token-standard/blob/06ad30ea8a8c27b6eaada9c214f39e8f50eb8d4b/canisters/dft_motoko/utils/PrincipalExt.mo in order to get it into mops. Please contact [email protected] if you are Deland-Labs would like take over ownership in mops.

# Principal Utilities Module

This project provides a module to work with Internet Computer (IC) Principals, including functions to decode and validate Principal strings, and determine the type of a Principal (canister or user).

## Overview

The module provides the following functionalities:
- `fromText`: Decodes a Principal from its textual representation and validates it. Returns null if it fails
- `isCanister`: Checks if a given Principal is a canister ID.
- `isUserPrincipal`: Checks if a given Principal is a user ID.

## Installation

```sh
mops add principal-ext
```

## Usage

### fromText

```motoko
let principal: ?Principal = PrincipalModule.fromText("aaaaa-aa");
```

The `fromText` function decodes a Principal from its textual representation and validates it. It returns an optional Principal (`?Principal`).

### isCanister

```motoko
let isCanister: Bool = PrincipalModule.isCanister(principal);
```

The `isCanister` function checks if a given Principal is a canister ID. It returns a boolean (`Bool`).

### isUserPrincipal

```motoko
let isUser: Bool = PrincipalModule.isUserPrincipal(principal);
```

The `isUserPrincipal` function checks if a given Principal is a user ID. It returns a boolean (`Bool`).

## License

This project is licensed under the Apache 2.0 license.
177 changes: 177 additions & 0 deletions src/Base32.mo
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
/// https://github.com/flyq/ic_codec/blob/8a6f2fff88758125fd7e3ce54f99366f9c121eda/src/base32.mo
/// This library lets you encode and decode in either RFC4648 Base32 or in Crockford Base32.

import Array "mo:base/Array";
import Iter "mo:base/Iter";
import Text "mo:base/Text";
import Char "mo:base/Char";
import Nat8 "mo:base/Nat8";
import Int8 "mo:base/Int8";
import Nat "mo:base/Nat";
import Nat32 "mo:base/Nat32";
import Int "mo:base/Int";

// refers: https://docs.rs/crate/base32/0.4.0/source/src/lib.rs
module {
let RFC4648_ALPHABET: [Nat8]= [65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 50, 51, 52, 53, 54, 55]; // b"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
let CROCKFORD_ALPHABET: [Nat8] = [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 74, 75, 77, 78, 80, 81, 82, 83, 84, 86, 87, 88, 89, 90]; // b"0123456789ABCDEFGHJKMNPQRSTVWXYZ"
let RFC4648_INV_ALPHABET: [Int8] = [-1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25];
let CROCKFORD_INV_ALPHABET: [Int8] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, 16, 17, 1, 18, 19, 1, 20, 21, 0, 22, 23, 24, 25, 26, -1, 27, 28, 29, 30, 31];

/// RFC4648 Base32 or Crockford Base32
public type Alphabet = {
#RFC4648: { padding: Bool; };
#Crockford;
};

/// encode the bytes
public func encode(alphabet: Alphabet, data: [Nat8]) : Text {
let (alpha, padding) = switch alphabet {
case (#RFC4648 { padding }) { (RFC4648_ALPHABET, padding); };
case (#Crockford) { (CROCKFORD_ALPHABET, false); };
};
let len =(data.size() + 3)/4*5;
var ret: [var Nat8] = [var];
var res: Text = "";
let chunks = bytesToChunks(data, 5);
for (i in chunks.keys()) {
let buf: [var Nat8] = Array.init<Nat8>(5, 0);
for (j in chunks[i].keys()) {
buf[j] := chunks[i][j];
};
ret := Array.thaw(Array.append(Array.freeze(ret), [alpha[Nat8.toNat((buf[0] & 0xF8) >> 3)]]));
ret := Array.thaw(Array.append(Array.freeze(ret), [alpha[Nat8.toNat(((buf[0] & 0x07) << 2) | ((buf[1] & 0xC0) >> 6))]]));
ret := Array.thaw(Array.append(Array.freeze(ret), [alpha[Nat8.toNat((buf[1] & 0x3E) >> 1)]]));
ret := Array.thaw(Array.append(Array.freeze(ret), [alpha[Nat8.toNat(((buf[1] & 0x01) << 4) | ((buf[2] & 0xF0) >> 4))]]));
ret := Array.thaw(Array.append(Array.freeze(ret), [alpha[Nat8.toNat(((buf[2] & 0x0F) << 1) | (buf[3] >> 7))]]));
ret := Array.thaw(Array.append(Array.freeze(ret), [alpha[Nat8.toNat((buf[3] & 0x7C) >> 2)]]));
ret := Array.thaw(Array.append(Array.freeze(ret), [alpha[Nat8.toNat(((buf[3] & 0x03) << 3) | ((buf[4] & 0xE0) >> 5))]]));
ret := Array.thaw(Array.append(Array.freeze(ret), [alpha[Nat8.toNat(buf[4] & 0x1F)]]));
};
var len_ret: Nat = ret.size();
if ((data.size() % 5) != 0) {
let len = ret.size();
var num_extra = 0;
if (8 < ((data.size() % 5 * 8 + 4) / 5)) {
num_extra := 0;
} else {
num_extra := 8 - ((data.size() % 5 * 8 + 4) / 5);
};
if padding {
for (i in Iter.range(1, num_extra)) {
ret[len - i] := 61; // b'=' == 61
};
} else {
len_ret := len - num_extra;
};
};
for (i in Iter.range(0, len_ret-1)) {
res := res # Char.toText(Char.fromNat32(Nat32.fromNat(Nat8.toNat(ret[i]) )));
};
return res;
};

/// decode the text
public func decode(alphabet: Alphabet, data: Text) : ?[Nat8] {
if (not is_ascii(data)) {
return null;
};
var bytes: [Nat8] = [];
for (i in Text.toIter(data)) {
bytes := Array.append(bytes, [Nat8.fromNat(Nat32.toNat(Char.toNat32(i)))]);
};
let alpha = switch (alphabet) {
case (#RFC4648 { padding }) { RFC4648_INV_ALPHABET; };
case (#Crockford) { CROCKFORD_INV_ALPHABET; };
};
var unpadded_bytes_length = bytes.size();
label l for (i in Iter.range(1, Nat.min(6, bytes.size()))) {
if (bytes[bytes.size() - i] != 61) { // b'=' == 61
break l;
};
unpadded_bytes_length -= 1;
};
let output_length = unpadded_bytes_length*5/8;
var ret: [Nat8] = [];
let ret_len = (output_length+4)/5*5;
let chunks = bytesToChunks(bytes, 8);
for (i in chunks.keys()) {
let buf: [var Nat8] = Array.init<Nat8>(8, 0);
for (j in chunks[i].keys()) {
switch (get_element(alpha, Nat8.toNat(wrapping_sub(to_ascii_uppercase(chunks[i][j]), 48)) )) { // b'0' == 48
case (?-1 or null) { return null; };
case (?val) { buf[j] := Int8.toNat8(val); };
}
};
ret := Array.append(ret, [((buf[0] << 3) | (buf[1] >> 2))]);
ret := Array.append(ret, [((buf[1] << 6) | (buf[2] << 1) | (buf[3] >> 4))]);
ret := Array.append(ret, [((buf[3] << 4) | (buf[4] >> 1))]);
ret := Array.append(ret, [((buf[4] << 7) | (buf[5] << 2)) | (buf[6] >> 3)]);
ret := Array.append(ret, [((buf[6] << 5) | buf[7])]);
};
var res = Array.init<Nat8>(output_length, 0);
for (i in res.keys()) {
res[i] := ret[i];
};
return ?Array.freeze(res);
};

func bytesToChunks(bytes: [Nat8], interval: Nat) : [[Nat8]] {
let len = bytes.size();
var ret: [[Nat8]] = [];
for (i in Iter.range(1, len)) {
var chunk: [var Nat8] = Array.init<Nat8>(interval, 0);
if (i % interval == 0) {
for (j in Iter.range(0, interval-1)) {
chunk[j] := bytes[i-(interval-j)];
};
ret := Array.append(ret, [Array.freeze(chunk)]);
};
};
if (len % interval != 0) {
var chunk: [Nat8] = [];
for (i in Iter.range(0, (len % interval) - 1)) {
chunk := Array.append<Nat8>(chunk, [bytes[len - (len % interval) + i]]);
};
ret := Array.append<[Nat8]>(ret, [chunk]);
};
return ret;
};

func is_ascii(a: Text) : Bool {
for (i in Text.toIter(a)) {
if (Char.toNat32(i) > 0x7F) {
return false;
};
};
return true;
};

func to_ascii_uppercase(a: Nat8) : Nat8 {
if (is_ascii_lowercase(Char.fromNat32(Nat32.fromNat(Nat8.toNat(a))))) {
return 32 ^ a;
} else {
return a;
};
};

func is_ascii_lowercase(a: Char) : Bool {
return (a >= 'a' and a <= 'z');
};

func get_element(a: [Int8], index: Nat) : ?Int8 {
if (index < a.size()) {
return ?a[index];
} else {
return null;
};
};

func wrapping_sub(a: Nat8, b: Nat8) : Nat8 {
if (a < b) {
return 255 - b + a + 1;
} else {
return a - b;
};
};
};
70 changes: 70 additions & 0 deletions src/Crc32.mo
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
CRC32.mo based on: https://github.com/enzoh/motoko-crc/blob/master/src/CRC8.mo
*/

import Prim "mo:prim";
import Nat "mo:base/Nat";
import Nat8 "mo:base/Nat8";
import Nat32 "mo:base/Nat32";

module {
private let tablecrc32 : [Nat32] = [
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
];

public func crc32(data : [Nat8]) : [Nat8] {
var crc : Nat32 = 4294967295;
for (byte in data.vals()) {
crc := (crc >> 8) ^ tablecrc32[Nat32.toNat((crc ^ Nat32.fromNat(Nat8.toNat(byte))) & 0xFF)];
};
crc := (crc ^ 0xFFFFFFFF) & 0xffffffff;
return [
Nat8.fromNat(Nat32.toNat((crc >> 24) & 0xFF)),
Nat8.fromNat(Nat32.toNat((crc >> 16) & 0xFF)),
Nat8.fromNat(Nat32.toNat((crc >> 8) & 0xFF)),
Nat8.fromNat(Nat32.toNat((crc) & 0xFF))
];
};
};
Loading

0 comments on commit b6c83f3

Please sign in to comment.