Skip to main content

Modules & Files

A module is one policy file.
  • Must start with a package
  • Optional imports
  • Then one or more rules
package app.auth

import data.roles
import data.helpers as H

default allow = false

Rules

Value Rules (with if/else bodies)

allow if {
  input.user == "admin"
} else if {
  input.action == "read"
}
  • Branching with else
  • Each block is a query of literals

Default Rules

default allow = false
  • Sets a fallback value if no other rule branch applies

Function Rules

allow(u, a) := true if {
  u == "admin"
} else if {
  a == "read"
}
  • Rules can take arguments, like functions

Set & Object Rules

# Set membership
my_ids[id] if {
  id := input.items[_].id
  id > 1000
}

# Object construction
user_roles[uid] := role if {
  role := data.roles[uid]
}

Comprehension Rules

allowed_names := [n | u := input.users[_]; u.allowed; n := u.name]
project_ids   := {p | p := input.projects[_].id}
role_by_user  := { u.id: u.role | u := input.users[_] }

Expressions & Queries

Literals

  • Expressions, not exprs
  • some existential, every universal
some i
not blocked[i]

every u in input.users { u.active }

Assignments & Comparisons

x := input.value
x in [1,2,3]
count(input.items) >= 5

Arithmetic & Boolean

total := price * quantity + tax
ok if input.age >= 18 and not input.banned

References & Calls

v1 := input.user.name
v2 := data.groups["admins"].members
r  := helper.add(2,3)

With Modifiers

allow with data.now as "2025-06-01T00:00:00Z"

Collections & Scalars

Arrays, Objects, Sets

a := [1,2,3]
o := {"x":1, "y":2}
s := {1,2,3}

Scalars & Variables

n := 42
s := "hello"
t := true
z := null

Quantifiers

  • some / every
some i in input.items
input.items[i].active

every u in input.users {
  u.age >= 18
}

Negation

  • not
deny if {
  not input.authenticated
}

Membership

  • in
"admin" in input.user.roles

Builtins (Supported Categories)

Aggregates

n := count(input.items)
sum_ok := sum([1,2,3]) == 6
min_val := min([4,9,1])

Arrays

array.slice([1,2,3,4], 1, 3)  # [2,3]

Sets

u := union({{1,2},{2,3}})

Objects

ks := object.keys({"a":1,"b":2})

Strings

ok := contains("hello world", "world")

Numbers

cl := ceil(3.2)  # 4

Time

ts := time.parse_rfc3339_ns("2024-01-01T00:00:00Z")

Conversions & Encoding

j := json.marshal({"x":1})

Regex

regex.match(`^\\d+$`, "12345")

Semver

semver.is_valid("1.2.3")

Newton Crypto Extensions

Newton extends the standard Rego runtime with custom cryptographic builtins for signature recovery. These are available in the Newton Regorus engine used by operators and the newton-cli regorus eval command.

newton.crypto.ecdsa_recover_signer

Recovers the signer address from a raw message hash and ECDSA signature.
signer := newton.crypto.ecdsa_recover_signer(signature, message_hash)
ParameterTypeDescription
signaturestringHex-encoded ECDSA signature (65 bytes with recovery id)
message_hashstringHex-encoded 32-byte message hash
Returns: Hex-encoded Ethereum address of the signer.

newton.crypto.ecdsa_recover_signer_personal

Recovers the signer address from a personal message and ECDSA signature. Applies the EIP-191 \x19Ethereum Signed Message:\n prefix before recovery.
signer := newton.crypto.ecdsa_recover_signer_personal(signature, message)
ParameterTypeDescription
signaturestringHex-encoded ECDSA signature (65 bytes with recovery id)
messagestringThe original message string (prefix is applied automatically)
Returns: Hex-encoded Ethereum address of the signer.

Example

package auth

default allow = false

allow if {
    signer := newton.crypto.ecdsa_recover_signer(input.intent_signature, input.intent_hash)
    signer == input.from
}

Newton Identity Extensions

Newton extends the Rego runtime with identity verification built-ins for checking user identity data within policies. Identity data is domain-namespaced — the identity_domain (bytes32) stored on-chain determines which schema and built-ins apply. Domain is always required. Two APIs are available:
  • Domain-namespaced built-ins (primary): newton.identity.kyc.age_gte(21). Type-safe with input validation and specific error messages.
  • Generic field accessor (escape hatch): newton.identity.get("field_name"). Returns the raw field value from the current domain’s data. Useful for rapid prototyping with new domains before dedicated built-ins exist.
Identity data is injected by Newton operators at evaluation time from the on-chain IdentityRegistry. Policy authors do not have direct access to personally identifying information — only the built-in check results (booleans) are exposed to the policy.

KYC Domain (newton.identity.kyc.*)

The KYC domain provides 8 built-ins for verifying Know Your Customer identity data.

KYC Data Fields

FieldTypeDescription
reference_dateYYYY-MM-DDTimestamp of “now” for time-based checks
statusstringKYC status: approved, pending, completed, failed, expired, declined
selected_country_codeISO 3166-1 alpha-2Country selected during KYC process
address_country_codeISO 3166-1 alpha-2Country from document address
address_subdivisionstringState/province from document address
birthdateYYYY-MM-DDDate of birth
expiration_dateYYYY-MM-DDDocument expiration date
issue_dateYYYY-MM-DDDocument issuance date
issuing_authoritystringIssuing country or state

newton.identity.kyc.check_approved

Returns true if the identity status is "approved".
result := newton.identity.kyc.check_approved()
No parameters. Returns bool.

newton.identity.kyc.address_in_countries

Checks if the document’s address country code is in the provided list.
result := newton.identity.kyc.address_in_countries(["US", "CA", "DE"])
ParameterTypeDescription
countriesstring[]Array of ISO 3166-1 alpha-2 country codes
Returns bool. Errors if the array is empty or the stored country code is empty.

newton.identity.kyc.address_in_subdivision

Checks if the document’s address subdivision is in the provided list.
result := newton.identity.kyc.address_in_subdivision(["US-CA", "US-OR", "US-WA"])
ParameterTypeDescription
subdivisionsstring[]Array of ISO subdivision codes (CC-SS format, e.g., US-CA)
Returns bool. The check concatenates address_country_code + - + address_subdivision and matches against the list. Errors if the array is empty or country/subdivision fields are empty.

newton.identity.kyc.address_not_in_subdivision

Inverse of address_in_subdivision. Returns true if the address is NOT in the list.
result := newton.identity.kyc.address_not_in_subdivision(["US-NY", "US-NC"])
ParameterTypeDescription
subdivisionsstring[]Array of ISO subdivision codes to exclude
Returns bool. Useful when combined with address_in_countries to include a country but exclude specific states.

newton.identity.kyc.age_gte

Checks if the person’s age (calculated from birthdate to reference_date) is at least the specified years.
result := newton.identity.kyc.age_gte(21)
ParameterTypeDescription
min_agenumberMinimum age in years (must be positive)
Returns bool. Errors if min_age is not positive or dates cannot be parsed.

newton.identity.kyc.not_expired

Returns true if the document expiration date has not passed relative to reference_date.
result := newton.identity.kyc.not_expired()
No parameters. Returns bool.

newton.identity.kyc.valid_for

Checks if the document will remain valid for at least the specified number of days.
result := newton.identity.kyc.valid_for(365)
ParameterTypeDescription
min_daysnumberMinimum days of remaining validity (must be positive)
Returns bool. Compares (expiration_date - reference_date) against the provided day count.

newton.identity.kyc.issued_since

Checks if the document was issued at least the specified number of days ago.
result := newton.identity.kyc.issued_since(90)
ParameterTypeDescription
min_daysnumberMinimum days since issuance (must be positive)
Returns bool. Compares (reference_date - issue_date) against the provided day count.

Generic Field Accessor (newton.identity.get)

Works across any identity domain. Returns the raw field value by name from the current domain’s data. Returns undefined if the field does not exist, allowing Rego default patterns.
result := newton.identity.get("field_name")
ParameterTypeDescription
field_namestringField name to look up
Returns the field value (any type), or undefined if not found. When multiple identity domains are registered, all domains’ fields are accessible through this single accessor.

KYC Policy Example

package kyc_compliance

default allow = false

# Allow transactions from approved US/CA users over 21 with valid documents
allow if {
    newton.identity.kyc.check_approved()
    newton.identity.kyc.age_gte(21)
    newton.identity.kyc.address_in_countries(["US", "CA"])
    newton.identity.kyc.address_not_in_subdivision(["US-NY", "US-NC"])
    newton.identity.kyc.not_expired()
    newton.identity.kyc.valid_for(90)
    newton.identity.kyc.issued_since(30)
}

Mixed Domain and Generic Accessor Example

package mixed_check

default allow = false

# Combine domain-specific built-ins with generic field access
allow if {
    newton.identity.kyc.check_approved()
    newton.identity.kyc.age_gte(18)
    newton.identity.get("address_country_code") == "US"
}

Adding New Identity Domains

The identity extension system is designed for new domains beyond KYC. Each domain (social, credit, professional, etc.) defines its own data struct, Rego built-ins, and field accessors. New domains register under newton.identity.<domain>.* and merge their fields into the shared newton.identity.get accessor. Until domain-specific built-ins are available for a new domain, policy authors can use newton.identity.get("field_name") to access any field from the domain’s data.

Privacy Extensions (newton.privacy.*)

Provider-managed confidential data (blacklists, allowlists, sanctions lists) uploaded via the ConfidentialDataRegistry. Operators fetch and decrypt this data at task time based on the confidential_domain in policyParams. Two access patterns:
  • Domain-namespaced builtins (primary): newton.privacy.blacklist.contains(addr). Type-safe with address normalization.
  • Generic field accessor (escape hatch): newton.privacy.get("field_name"). Returns raw field values across all registered privacy domains.

Blacklist Domain (newton.privacy.blacklist.*)

newton.privacy.blacklist.contains

result := newton.privacy.blacklist.contains(address)
Returns true if address is in the provider’s blacklist. Addresses are normalized to lowercase hex before comparison.

newton.privacy.blacklist.count

result := newton.privacy.blacklist.count()
Returns the number of addresses in the blacklist.

Allowlist Domain (newton.privacy.allowlist.*)

newton.privacy.allowlist.contains

result := newton.privacy.allowlist.contains(address)
Returns true if address is in the provider’s allowlist.

newton.privacy.allowlist.count

result := newton.privacy.allowlist.count()
Returns the number of addresses in the allowlist.

Generic Field Accessor (newton.privacy.get)

value := newton.privacy.get("field_name")
Returns undefined if the field does not exist, which allows default rules to apply.

Privacy Policy Examples

Blacklist check (deny blacklisted senders)

package sanctions_check

default allow := false

allow if {
    not newton.privacy.blacklist.contains(input.from)
}

Allowlist check (only allow approved addresses)

package allowlist_only

default allow := false

allow if {
    newton.privacy.allowlist.contains(input.from)
}

Combined identity + privacy check

package compliant_transfer

default allow := false

allow if {
    # User must pass KYC
    newton.identity.kyc.check_approved()
    newton.identity.kyc.age_gte(18)
    # Sender must not be blacklisted
    not newton.privacy.blacklist.contains(input.from)
    # Recipient must be on allowlist
    newton.privacy.allowlist.contains(input.to)
}

Time Extensions (newton.time.*)

Date arithmetic builtins for time-based policy checks. All dates use YYYY-MM-DD format strings.

newton.time.days_between

result := newton.time.days_between(date_a, date_b)
Returns the absolute number of days between two dates.

newton.time.days_since

result := newton.time.days_since(past_date, reference_date)
Returns positive days if past_date is before reference_date.

newton.time.is_within_days

result := newton.time.is_within_days(date, reference_date, max_days)
Returns true if the absolute difference between date and reference_date is at most max_days.

newton.time.is_before / newton.time.is_after

result := newton.time.is_before(date_a, date_b)
result := newton.time.is_after(date_a, date_b)

newton.time.age_years

result := newton.time.age_years(birthdate, reference_date)
Returns the number of complete years between birthdate and reference_date. Useful for age verification without the KYC identity domain.

Time Policy Example

package time_check

default allow := false

# Allow if document was issued within the last 90 days
allow if {
    newton.time.is_within_days(data.issued_date, data.reference_date, 90)
}

Not Yet Supported

  • Standard Crypto / Tokens / JWT: crypto.*, jwtverify*, jwtencode* — use Newton crypto extensions instead
  • HTTP: http.send — not implemented (use PolicyData WASM oracles for external data)
  • GraphQL: graphql.* — not implemented
  • Glob matching: regex.globs_match — not implemented
  • JSON Patch: json.patch — not implemented
  • Networking: net.* — not implemented
  • AWS Providers: providers.aws.* — not implemented
  • Rego Meta: rego.metadata.*, rego.parse_module — not implemented
  • Template rendering: strings.render_template — not implemented