Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
31 changes: 30 additions & 1 deletion noir/aztec_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -620,7 +620,21 @@ fn create_context(ty: &str, params: &[Param]) -> Vec<Statement> {
UnresolvedTypeData::Integer(..) | UnresolvedTypeData::Bool => {
add_cast_to_hasher(identifier)
}
_ => unreachable!("[Aztec Noir] Provided parameter type is not supported"),
UnresolvedTypeData::String(..) => {
let (var_bytes, id) = str_to_bytes(identifier);
injected_expressions.push(var_bytes);
add_array_to_hasher(
&id,
&UnresolvedType {
typ: UnresolvedTypeData::Integer(Signedness::Unsigned, 32),
span: None,
},
)
}
_ => panic!(
"[Aztec Noir] Provided parameter type: {:?} is not supported",
unresolved_type
),
};
injected_expressions.push(expression);
}
Expand Down Expand Up @@ -909,6 +923,21 @@ fn add_struct_to_hasher(identifier: &Ident) -> Statement {
)))
}

fn str_to_bytes(identifier: &Ident) -> (Statement, Ident) {
// let identifier_as_bytes = identifier.as_bytes();
let var = variable_ident(identifier.clone());
let contents = if let ExpressionKind::Variable(p) = &var.kind {
p.segments.first().cloned().unwrap_or_else(|| panic!("No segments")).0.contents
} else {
panic!("Unexpected identifier type")
};
let bytes_name = format!("{}_bytes", contents);
let var_bytes = assignment(&bytes_name, method_call(var, "as_bytes", vec![]));
let id = Ident::new(bytes_name, Span::default());

(var_bytes, id)
}

fn create_loop_over(var: Expression, loop_body: Vec<Statement>) -> Statement {
// If this is an array of primitive types (integers / fields) we can add them each to the hasher
// casted to a field
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ ecdsa_secp256k1_verify(
signature): boolean
```

Calculates the Blake2s256 hash of the input bytes and represents these as a single field element.
Verifies a ECDSA signature over the secp256k1 curve.

## Parameters
Expand Down
2 changes: 1 addition & 1 deletion noir/docs/docs/reference/NoirJS/noir_js/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
| :------ | :------ |
| [and](functions/and.md) | Performs a bitwise AND operation between `lhs` and `rhs` |
| [blake2s256](functions/blake2s256.md) | Calculates the Blake2s256 hash of the input bytes |
| [ecdsa\_secp256k1\_verify](functions/ecdsa_secp256k1_verify.md) | Calculates the Blake2s256 hash of the input bytes and represents these as a single field element. |
| [ecdsa\_secp256k1\_verify](functions/ecdsa_secp256k1_verify.md) | Verifies a ECDSA signature over the secp256k1 curve. |
| [ecdsa\_secp256r1\_verify](functions/ecdsa_secp256r1_verify.md) | Verifies a ECDSA signature over the secp256r1 curve. |
| [keccak256](functions/keccak256.md) | Calculates the Keccak256 hash of the input bytes |
| [sha256](functions/sha256.md) | Calculates the SHA256 hash of the input bytes |
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod bool_serialization;
mod field_serialization;
mod u8_serialization;
mod u32_serialization;
mod address_serialization;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use crate::types::type_serialization::TypeSerializationInterface;

global U8_SERIALIZED_LEN: Field = 1;

fn deserializeU8(fields: [Field; U8_SERIALIZED_LEN]) -> u8 {
fields[0] as u8
}

fn serializeU8(value: u8) -> [Field; U8_SERIALIZED_LEN] {
[value as Field]
}

global U8SerializationMethods = TypeSerializationInterface {
deserialize: deserializeU8,
serialize: serializeU8,
};
9 changes: 9 additions & 0 deletions yarn-project/aztec-nr/compressed-string/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "compressed_string"
authors = [""]
compiler_version = ">=0.18.0"
type = "lib"

[dependencies]
aztec = {path = "../aztec"}
protocol_types = {path = "../../noir-protocol-circuits/src/crates/types"}
142 changes: 142 additions & 0 deletions yarn-project/aztec-nr/compressed-string/src/compressed_string.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
use dep::aztec::types::type_serialization::TypeSerializationInterface;
use dep::protocol_types::utils::field::field_from_bytes;
use dep::std;

// A Fixedsize Compressed String.
// Essentially a special version of Compressed String for practical use.
struct FieldCompressedString{
value: Field
}

impl FieldCompressedString{
pub fn is_eq(self, other: FieldCompressedString) -> bool {
self.value == other.value
}

pub fn from_field(input_field: Field) -> Self {
Self {value: input_field}
}

pub fn from_string(input_string: str<31>) -> Self {
Self {value: field_from_bytes(input_string.as_bytes(), true)}
}

pub fn to_bytes(self) -> [u8; 31] {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for my understanding - why 31 and not 32?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

32 * 8 = 256. We don't have that many bits to use in a field.

let mut result = [0; 31];
let bytes = self.value.to_be_bytes(31);
for i in 0..31 {
result[i] = bytes[i];
}
result
}

pub fn serialize(self) -> [Field; 1] {
[self.value]
}

pub fn deserialize(input: [Field; 1]) -> Self {
Self { value: input[0] }
}
}

fn deserialize(fields: [Field; 1]) -> FieldCompressedString {
FieldCompressedString { value: fields[0] }
}

fn serialize(value: FieldCompressedString) -> [Field; 1] {
value.serialize()
}
global FieldCompressedStringSerializationMethods = TypeSerializationInterface {
deserialize,
serialize,
};

// The general Compressed String.
// Compresses M bytes into N fields.
// Can be used for longer strings that don't fit in a single field.
// Each field can store 31 characters, so N should be M/31 rounded up.
struct CompressedString<N, M> {
Comment thread
benesjan marked this conversation as resolved.
value: [Field; N]
}

impl<N, M> CompressedString<N, M> {
pub fn from_string(input_string: str<M>) -> Self {
let mut fields = [0; N];
let byts = input_string.as_bytes();

let mut r_index = 0 as u32;

for i in 0..N {
let mut temp = [0 as u8; 31];
for j in 0..31 {
if r_index < M {
temp[j] = byts[r_index];
r_index += 1;
}
}

fields[i] = field_from_bytes(temp, true);
}

Self { value: fields }
}

pub fn to_bytes(self) -> [u8; M] {
let mut result = [0; M];
let mut w_index = 0 as u32;
for i in 0..N {
let bytes = self.value[i].to_be_bytes(31);
for j in 0..31 {
if w_index < M {
result[w_index] = bytes[j];
w_index += 1;
}
}
}
result
}

pub fn serialize(self) -> [Field; N] {
self.value
}

pub fn deserialize(input: [Field; N]) -> Self {
Self { value: input }
}
}

#[test]
fn test_short_string() {
let i = "Hello world";
let b = i.as_bytes();
let name: CompressedString<1,11> = CompressedString::from_string(i);
let p = b == name.to_bytes();
assert(p, "invalid recover");
}

#[test]
fn test_long_string() {
let i = "Hello world. I'm setting up a very long text of blibbablubb such that we can see if works as planned for longer names.";
let b = i.as_bytes();
let name: CompressedString<4,118> = CompressedString::from_string(i);
let p = b == name.to_bytes();
assert(p, "invalid recover");
}

#[test]
fn test_long_string_work_with_too_many_fields() {
let i = "Hello world. I'm setting up a very long text of blibbablubb such that we can see if works as planned for longer names.";
let b = i.as_bytes();
let name: CompressedString<5,118> = CompressedString::from_string(i);
let p = b == name.to_bytes();
assert(p, "invalid recover");
}

#[test(should_fail)]
fn test_long_string_fail_with_too_few_fields() {
let i = "Hello world. I'm setting up a very long text of blibbablubb such that we can see if works as planned for longer names.";
let b = i.as_bytes();
let name: CompressedString<3,118> = CompressedString::from_string(i);
let p = b == name.to_bytes();
assert(p, "invalid recover");
}
4 changes: 4 additions & 0 deletions yarn-project/aztec-nr/compressed-string/src/lib.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
mod compressed_string;

use crate::compressed_string::{CompressedString};
use crate::compressed_string::{FieldCompressedString, FieldCompressedStringSerializationMethods};
2 changes: 1 addition & 1 deletion yarn-project/aztec-sandbox/src/examples/token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ async function main() {
logger(`Created Alice and Bob accounts: ${alice.address.toString()}, ${bob.address.toString()}`);

logger('Deploying Token...');
const token = await TokenContract.deploy(aliceWallet, alice).send().deployed();
const token = await TokenContract.deploy(aliceWallet, alice, 'TokenName', 'TokenSymbol', 18).send().deployed();
logger('Token deployed');

// Create the contract abstraction and link it to Alice's and Bob's wallet for future signing
Expand Down
2 changes: 2 additions & 0 deletions yarn-project/cli/src/encoding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ function encodeArg(arg: string, abiType: ABIType, name: string): any {
} else {
throw Error(`Invalid boolean value passed for ${name}: ${arg}.`);
}
} else if (kind === 'string') {
return arg;
} else if (kind === 'array') {
let arr;
const res = [];
Expand Down
3 changes: 2 additions & 1 deletion yarn-project/end-to-end/src/cli_docs_sandbox.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ LendingContractArtifact
ParentContractArtifact
PendingCommitmentsContractArtifact
PriceFeedContractArtifact
ReaderContractArtifact
SchnorrAccountContractArtifact
SchnorrHardcodedAccountContractArtifact
SchnorrSingleKeyAccountContractArtifact
Expand Down Expand Up @@ -255,7 +256,7 @@ Accounts found:
// Test deploy
docs = `
// docs:start:deploy
% aztec-cli deploy TokenContractArtifact --args $ADDRESS
% aztec-cli deploy TokenContractArtifact --args $ADDRESS TokenName TKN 18

Contract deployed at 0x1ae8eea0dc265fb7f160dae62cc8912686d8a9ed78e821fbdd8bcedc54c06d0f
// docs:end:deploy
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/end-to-end/src/e2e_2_pxes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ describe('e2e_2_pxes', () => {

const deployTokenContract = async (initialAdminBalance: bigint, admin: AztecAddress, pxe: PXE) => {
logger(`Deploying Token contract...`);
const contract = await TokenContract.deploy(walletA, admin).send().deployed();
const contract = await TokenContract.deploy(walletA, admin, 'TokenName', 'TokenSymbol', 18).send().deployed();

if (initialAdminBalance > 0n) {
await mintTokens(contract, admin, initialAdminBalance, pxe);
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/end-to-end/src/e2e_block_building.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ describe('e2e_block_building', () => {

// Deploy a contract in the first transaction
// In the same block, call a public method on the contract
const deployer = TokenContract.deploy(owner, owner.getCompleteAddress());
const deployer = TokenContract.deploy(owner, owner.getCompleteAddress(), 'TokenName', 'TokenSymbol', 18);
await deployer.create();

// We can't use `TokenContract.at` to call a function because it checks the contract is deployed
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/end-to-end/src/e2e_cheat_codes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ describe('e2e_cheat_codes', () => {
rollupAddress = deployL1ContractsValues.l1ContractAddresses.rollupAddress;
admin = accounts[0];

token = await TokenContract.deploy(wallet, admin).send().deployed();
token = await TokenContract.deploy(wallet, admin, 'TokenName', 'TokenSymbol', 18).send().deployed();
}, 100_000);

afterAll(() => teardown());
Expand Down
14 changes: 12 additions & 2 deletions yarn-project/end-to-end/src/e2e_deploy_contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,18 @@ describe('e2e_deploy_contract', () => {
try {
// This test requires at least another good transaction to go through in the same block as the bad one.
// I deployed the same contract again but it could really be any valid transaction here.
const goodDeploy = new ContractDeployer(TokenContractArtifact, wallet).deploy(AztecAddress.random());
const badDeploy = new ContractDeployer(TokenContractArtifact, wallet).deploy(AztecAddress.ZERO);
const goodDeploy = new ContractDeployer(TokenContractArtifact, wallet).deploy(
AztecAddress.random(),
'TokenName',
'TKN',
18,
);
const badDeploy = new ContractDeployer(TokenContractArtifact, wallet).deploy(
AztecAddress.ZERO,
'TokenName',
'TKN',
18,
);

await Promise.all([
goodDeploy.simulate({ skipPublicSimulation: true }),
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/end-to-end/src/e2e_escrow_contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ describe('e2e_escrow_contract', () => {
logger(`Escrow contract deployed at ${escrowContract.address}`);

// Deploy Token contract and mint funds for the escrow contract
token = await TokenContract.deploy(wallet, owner).send().deployed();
token = await TokenContract.deploy(wallet, owner, 'TokenName', 'TokenSymbol', 18).send().deployed();

const mintAmount = 100n;
const secret = Fr.random();
Expand Down
8 changes: 6 additions & 2 deletions yarn-project/end-to-end/src/e2e_lending_contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,18 @@ describe('e2e_lending_contract', () => {

{
logger(`Deploying collateral asset feed contract...`);
const receipt = await waitForSuccess(TokenContract.deploy(wallet, accounts[0]).send());
const receipt = await waitForSuccess(
TokenContract.deploy(wallet, accounts[0], 'TokenName', 'TokenSymbol', 18).send(),
);
logger(`Collateral asset deployed to ${receipt.contractAddress}`);
collateralAsset = await TokenContract.at(receipt.contractAddress!, wallet);
}

{
logger(`Deploying stable coin contract...`);
const receipt = await waitForSuccess(TokenContract.deploy(wallet, accounts[0]).send());
const receipt = await waitForSuccess(
TokenContract.deploy(wallet, accounts[0], 'TokenName', 'TokenSymbol', 18).send(),
);
logger(`Stable coin asset deployed to ${receipt.contractAddress}`);
stableCoin = await TokenContract.at(receipt.contractAddress!, wallet);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ describe('e2e_multiple_accounts_1_enc_key', () => {
}

logger(`Deploying Token...`);
const token = await TokenContract.deploy(wallets[0], accounts[0]).send().deployed();
const token = await TokenContract.deploy(wallets[0], accounts[0], 'TokenName', 'TokenSymbol', 18).send().deployed();
tokenAddress = token.address;
logger(`Token deployed at ${tokenAddress}`);

Expand Down
2 changes: 1 addition & 1 deletion yarn-project/end-to-end/src/e2e_sandbox_example.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ describe('e2e_sandbox_example', () => {
logger(`Deploying token contract...`);

// Deploy the contract and set Alice as the admin while doing so
const contract = await TokenContract.deploy(aliceWallet, alice).send().deployed();
const contract = await TokenContract.deploy(aliceWallet, alice, 'TokenName', 'TokenSymbol', 18).send().deployed();
logger(`Contract successfully deployed at address ${contract.address.toShortString()}`);

// Create the contract abstraction and link it to Alice's wallet for future signing
Expand Down
Loading